继承(Inheritance)

news2024/11/15 18:01:46

 Odoo的一个强大方面是它的模块化。模块专用于业务需求,但模块也可以相互交互。这对于扩展现有模块的功能非常有用。例如,在我们的房地产场景中,我们希望在常规用户视图中直接显示销售人员的财产列表。

在介绍特定的Odoo模块继承之前,让我们看看如何更改标准CRUD(创建、检索,更新或删除)方法的行为

Python继承(Python Inheritance)

目标:

  • 不能删除状态不为New、Canceled的房产

    预期效果动画地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/unlink.gif

  • 房产收到报价时,房产状态应该改成‘Offer Received’

  • 不能以低于现有报价的价格创建报价

    预期效果动画地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/create.gif

在我们的房地产模块中,我们从不需要开发任何特定的东西来执行标准的CRUD操作。Odoo框架提供了实现这些操作的必要工具。事实上,多亏经典的Python继承,我们的模型中已经包含了这样的操作:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test.model"
    _description = "Test Model"

    ...

我们的 TestModel 类继承与Model,该Model类提供了 create(), read(), write() 和unlink()方法。

这些方法(和其它在Model中定义的任何方法)可被扩展以添加指定业务逻辑:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test.model"
    _description = "Test Model"

    ...

    @api.model
    def create(self, vals):
        # Do some business logic, modify vals...
        ...
        # Then call super to execute the parent method
        return super().create(vals)

model()装饰器对于create() 方法来说是必需的,因为结果集self的内容和创建(creation)的上下文无关,但该装饰器对于其它CRUD方法来说不是必需的。

Python 3中, super() 等价于 super(TestModel, self)。当你需要使用一条被修改后的结果集调用父方法时,可能需要使用后者。

危险提示

  • 总是调用 super()以避免中断流非常重要。只有少数非常特殊的情况才无需调用它。
  • 总是返回和父方法一致的数据。例如父方法返回一个dict(),你重写父方法时也要返回一个dict()

练习--添加业务逻辑到CRUD方法

  • 如果房产记录状态不是NewCanceled,则不让删除

提示:重写unlink() ,并记住self可以是一个包含多条记录的结果集。

  • 创建报价时,设置房产状态为‘Offer Received’,如果用户试图以低于已存在报价的金额创建报价时抛出错误。

提示: 可在vals中获取property_id 字段,但是它是一个int型。要实例化一个estate.property 对象,请使用self.env[model_name].browse(value) (示例)

    @api.model
    def create(self, vals):
        self.env['gamification.badge'].browse(vals['badge_id']).check_granting()
        return super(BadgeUser, self).create(vals)

修改odoo14\custom\estate\views\estate_property_views.xml 去掉estate_property_view_tree 中<tree>元素的editable="top"属性(说明:为了方便执行报价创建操作)

修改odoo14\custom\estate\models\estate_property.py

    @api.constrains('selling_price', 'expected_price')
    def _check_selling_price(self):
        # if record.selling_price < self.expected_price * 0.9:
        #     raise ValidationError("selling price can`t not lower then 90 percent of expected price")
        pass

说明:为了方便实践操作,暂且不做售价校验

最末尾新增以下代码

    def unlink(self):
        for record in self:
            if record.state not in ['New', 'Canceled']:
                raise UserError('can`t delete property which status is New or Canceled')
        return super().unlink()

修改odoo14\custom\estate\models\estate_property_offer.py,导入UserError

from odoo.exceptions import UserError

最末尾添加一下代码

    @api.model
    def create(self, vals):
        property = self.env['estate.property'].browse(vals['property_id'])
        
        if vals.get('price') < property.best_price:
            raise  UserError('不能低于现有报价')
        property.state = 'Offer Received'
        return super().create(vals)

重启服务,刷新浏览器验证

删除非NewCanceled状态的房产,提示如下:

 

模块继承(Model Inheritance)

引用: 查看主题相关文档继承和扩展

我们希望在“Settings/Users & Companies/Users”表单视图中直接显示与销售人员关联的房产列表。为此,我们需要向res.users模型添加一个字段,并调整其视图以显示它。

Odoo提供了两种继承机制来以模块化的方式扩展现有模型。

第一继承机制允许模块通过以下方式修改在另一个模块中定义的模型的行为:

  • 向模型添加字段

  • 覆盖模型中字段的定义

  • 给模型添加约束

  • 给模型添加方法

  • 重写模型中的现有方法

第二种继承机制(委托)允许将模型的每个记录链接到父模型的记录,并提供对该父记录的字段的透明访问。

odoo中,第一种机制最常用。在我们的例子中,我们希望向现有模型添加一个字段,这意味着我们将使用第一种机制。例如:

from odoo import fields, models

class InheritedModel(models.Model):
    _inherit = "inherited.model"

    new_field = fields.Char(string="New Field")

这里可以找到将两个字段添加到模型中的示例

class AccountMoveLine(models.Model):
    _inherit = 'account.move.line'

    vehicle_id = fields.Many2one('fleet.vehicle', string='Vehicle')
    need_vehicle = fields.Boolean(compute='_compute_need_vehicle',
        help="Technical field to decide whether the vehicle_id field is editable")

    def _compute_need_vehicle(self):
        self.need_vehicle = False

按照惯例,每个继承的模型都在其自己的Python文件中定义。在我们的示例中为“models/inherited_model.py”。

练习--添加字段到用户模型

  • 添加一下字段到res.users:
FieldType
property_idsOne2many inverse of salesman_id to estate.property
  • 添加一个domain到该字段,这样以便仅显示可获取房产。

新增odoo14\custom\estate\models\estate_res_user.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from odoo import models, fields

class EstateResUser(models.Model):
    _inherit = 'res.users'

    property_ids = fields.One2many('estate.property', 'salesman_id', domain="[('salesman_id', '=', active_id)]")

修改odoo14\custom\estate\models\__init__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
from . import estate_property
from . import estate_res_user # 本次新增

视图继承(View Inheritance)

参考: 主题关联文档可查看Inheritance.

目标: 在用户表单视图中显示与销售人员关联的avaliable房产列表其用户表单视图

Odoo提供了视图继承,其中子“扩展”视图应用于根视图之上,而不是就地修改现有视图(通过重写它们)。这些扩展既可以添加内容,也可以从父视图中删除内容。

扩展视图使用inherit_id字段引用其父视图。它的arch字段包含多个xpath元素,用于选择和更改父视图的内容,而不是单个视图:

<record id="inherited_model_view_form" model="ir.ui.view">
    <field name="name">inherited.model.form.inherit.test</field>
    <field name="model">inherited.model</field>
    <field name="inherit_id" ref="inherited.inherited_model_view_form"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             new_field after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="new_field"/>
        </xpath>
    </field>
</record>
  • expr

    一个用于选择父视图中单个元素的XPath表达式。如果不匹配任何元素或者匹配多个元素,则抛出错误

  • position

    应用于匹配元素的操作:

    inside

    xpath的主体附加到匹配元素的末尾(个人理解,添加为匹配元素的子元素)

    replace

    将匹配元素替换为xpath的主体,将新主体中出现的任何$0节点替换为原始元素

    before

    在匹配元素之前插入xpath的主体作为同级元素

    after

    在匹配的元素之后插入xpaths的主体,作为同级元素

    attributes

    使用xpath主体中的特定属性元素更改匹配元素的属性

当匹配单个元素时,可以直接在要查找的元素上设置position属性。以下两种继承都有相同的结果

<xpath expr="//field[@name='description']" position="after">
    <field name="idea_ids" />
</xpath>

<field name="description" position="after">
    <field name="idea_ids" />
</field>

在这里可以找到视图继承扩展的示例

<?xml version='1.0' encoding='utf-8'?>
<odoo>
    <record id="view_move_form" model="ir.ui.view">
        <field name="name">account.move.form</field>
        <field name="model">account.move</field>
        <field name="inherit_id" ref="account.view_move_form"/>
        <field name="arch" type="xml">
            <xpath expr="//field[@name='line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
            <xpath expr="//field[@name='invoice_line_ids']//field[@name='account_id']" position="after">
                <field name='need_vehicle' invisible='1'/>
                <field name='vehicle_id' attrs="{'required': [('need_vehicle', '=', True), ('parent.move_type', '=', 'in_invoice')], 'column_invisible': [('parent.move_type', '!=', 'in_invoice')]}" optional='hidden'/>
            </xpath>
        </field>
    </record>
</odoo>

练习--添加字段到用户视图

添加property_ids字段到 base.view_users_form 中新建的notebook

提示: 可以在 这里找到继承用户视图的示例。

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>

    <record id="res_users_view_form" model="ir.ui.view">
        <field name="name">res.users.view.form.inherit.gamification</field>
        <field name="model">res.users</field>
        <field name="inherit_id" ref="base.view_users_form"/>
        <field name="arch" type="xml">
            <group name="messaging" position="inside">
                <field name="karma"/>
            </group>
        </field>
    </record>

</data>
</odoo>

新增odoo14\custom\estate\views\estate_res_users_views.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
    <record id="estate_res_users_view_form" model="ir.ui.view">
        <field name="name">estate.res.users.view.form</field>
        <field name="model">res.users</field>
        <field name="inherit_id" ref="base.view_users_form"/>
        <field name="arch" type="xml">
            <xpath expr="//page[@name='references']" position="after">
                <page string="Real Estate Properties" name="RealEstateProperties">
                    <field name='property_ids'/>
                </page>
            </xpath>
        </field>
    </record>
</data>
</odoo>

修改odoo14\custom\estate\__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':['security/ir.model.access.csv',
            'views/estate_property_views.xml',
            'views/estate_property_type_views.xml',
            'views/estate_property_tag_views.xml',
            'views/estate_property_offer_views.xml',
            'views/estate_menus.xml',
            'views/estate_res_users_views.xml' # 本次新增
            ]
}

重启服务,验证效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/838832.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue diff 双端比较算法

文章目录 双端指针比较策略命中策略四命中策略二命中策略三命中策略一未命中四种策略&#xff0c;遍历旧节点列表新增情况一新增情况二 删除节点双端比较的优势 双端指针 使用四个变量 oldStartIdx、oldEndIdx、newStartIdx 以及 newEndIdx 分别存储旧 children 和新 children …

26 MFC序列化函数

文章目录 Serialize对于存储文件的序列化 Serialize Serialize 是一个在 MFC (Microsoft Foundation Classes) 中常用的函数或概念。它用于将对象的数据进行序列化和反序列化&#xff0c;便于在不同的场景中保存、传输和恢复对象的状态。 在 MFC 中&#xff0c;Serialize 函数…

如何查询显卡算力

感谢阅读 找到demo_suite此目录下打开控制台 找到demo_suite 一般在 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\extras\demo_suite 这个目录 注意&#xff1a; 1.V后面的数字表示版本&#xff0c;请根据自己的版本进行更改 2.此目录为我的安装目录&#xff0…

python批量检查folder中的文件是否符合要求

目录 问题描述&#xff1a; 问题解决&#xff1a; 问题描述&#xff1a; 最近在手动整理一些文档&#xff0c;要求是每一个folder以ID命名&#xff0c;每一个folder中存放三个内容&#xff08;如下图&#xff09;。如何实现批量检查每一个folder三个内容是否存在&#xff1f;…

【2023年电赛国一必备】E题报告模板--可直接使用

创作不易&#xff0c;麻烦关注CSDN【技术交流、免费报告资料】 通过百度网盘分享的文件&#xff1a;https://pan.baidu.com/s/1aXzYwLMLx_b59abvplUiYw?pwddn71 提取码:dn71 复制这段内容打开「百度网盘APP 即可获取」 任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部…

K8s实战入门(三)

文章目录 3. 实战入门3.1 Namespace3.1.1 测试两个不同的名称空间之间的 Pod 是否连通性 3.2 Pod3.3 Label3.4 Deployment3.5 Service 3. 实战入门 本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 3.1 Namespace Namespace是kuber…

【电源专题】充电IC与DC-DC有什么区别

充电IC和DC-DC一样使用很广泛,如手机、平板等需要电池供电的系统中,一般都会见到充电IC的身影。那么大家有没有考虑过一个问题。充电IC与DC-DC有什么区别? 首先如下所示为充电IC的两个阶段,一个阶段是恒流充电阶段,我们一般称之为CC阶段,另一个是恒压充电阶段,我们称之为…

Java课题笔记~ IoC 控制反转

二、IoC 控制反转 控制反转&#xff08;IoC&#xff0c;Inversion of Control&#xff09;&#xff0c;是一个概念&#xff0c;是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器&#xff0c;通过容器来实现对象的 装配和管理。控制反转就是对对象控制权的转移&a…

ShaderToy着色器移植到Three.js全过程记录

推荐&#xff1a;用 NSDT设计器 快速搭建可编程3D场景。 作为 Publicis Pixelpark Innovationlab 研究的一部分&#xff0c;我们研究了如何将较低底层的语言用于网络技术。 显而易见的选择似乎是 asm.js 或 WebAssembly。 但你也可以使用 WebGL 着色器来解决面向机器的问题。 …

springboot+vue网红酒店客房预定系统的设计与实现_ui9bt

随着计算机技术发展&#xff0c;计算机系统的应用已延伸到社会的各个领域&#xff0c;大量基于网络的广泛应用给生活带来了十分的便利。所以把网红酒店预定管理与现在网络相结合&#xff0c;利用计算机搭建网红酒店预定系统&#xff0c;实现网红酒店预定的信息化。则对于进一步…

【验证测试】未初始化的全局变量和局部变量的初值

验证目标&#xff1a; 未初始化的全局变量的初值为 0未初始化的局部变量的初值为随机值 测试用例&#xff1a; #include <stdio.h>char gval1; int gval2; static long gval3;int main() {unsigned char uchTmp1;unsigned int uTmp2;printf("%d\n", gval1)…

Word中如何断开表格中线段

Word中如何断开表格中线段_word表格断线怎么弄_仰望星空_LiDAR的博客-CSDN博客有时候为了美观&#xff0c;需要实现如下的效果&#xff0c;即第2条线段被断开成3段步骤如下&#xff1a;选中需要断开的格网&#xff0c;如下&#xff0c;再选择段落、针对下框标即可。_word表格断…

Verilog学习记录-自用

always语句块一定条件写完整&#xff0c;否则电平触发&#xff0c;综合生成锁存器 task不可综合&#xff0c;主要用于仿真/验证 大部分都是并行执行的&#xff0c;只有begin end块中阻塞语句是串行 if-else和case的区别 if-else面积小&#xff0c;但时延&#xff08;执…

Service not registered 异常导致手机重启分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、Service not registered 异常导致手机重启二、Service not registered 解决方案 一、Service not registered 异常导致手机重启 1.重启 的部分Log如…

C++封装思想之二:友元机制和运算符重载(1W字详解)

目录 友元机制和运算符重载 友元机制 友元函数 友元的作用 友元类 前置声明 友元类的注意事项 友元成员函数&#xff08;类的某个成员函数 作为另一个类的友元&#xff09; 运算符重载 运算符重载的作用 运算符重载的注意事项 运算符重载的实现 成员函数重载 友…

2021-03-03 Multisim 14.0 电池充电防止反接保护

R2R3当作充电线电阻看,也可设置这2个电阻导线电阻,电阻取值依据充电电流范围确定,由于电池存在电压因此可以用光耦检测,发光二极管当作继电器看,可采用继电器自锁,当下次再次反接的话另一个继电器同样,2个继电器相互控制.本电路可验证极性变化时2路检测的变化,图中S1为模拟电池…

计算机视觉:替换万物Inpaint Anything

目录 1 Inpaint Anything介绍 1.1 为什么我们需要Inpaint Anything 1.2 Inpaint Anything工作原理 1.3 Inpaint Anything的功能是什么 1.4 Segment Anything模型&#xff08;SAM&#xff09; 1.5 Inpaint Anything 1.5.1 移除任何物体 1.5.2 填充任意内容 1.5.3 替换任…

Finalshell连接Linux超时之Connection timed out: connect

目录 &#x1f349;前言 &#x1f33c;报错 &#x1f33c;摸索 &#x1f4aa;解决措施 &#x1f349;前言 &#xff08;1&#xff09;福利&#xff1a;花了2小时才解决的BUG&#xff0c;希望本篇文章能帮你10分钟解决&#xff01; &#xff08;2&#xff09;tips&#xff1…

6.s081/6.1810(Fall 2022)Lab3: page tables

文章目录 前言其他篇章参考链接0. 前置环境1. Speed up system calls (easy)1.1 简单分析1.2 映射1.3 页分配1.4 页释放1.5 测试 2. Print a page table (easy)2.1 简单分析2.2 实现2.3 测试 3. Detect which pages have been accessed (hard)3.1 简单分析3.2 实现3.2.1 获取参…

DBSCAN聚类

一、概述 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法&#xff0c;簇集的划定完全由样本的聚集程度决定。聚集程度不足以构成簇落的那些样本视为噪声点&#xff0c;因此DBSCAN聚类的方式也可以用于异常点的检测。 二、算法…