- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
Odoo的一个强大方面是它的模块化。模块专用于业务需求,但模块也可以相互交互。这对于扩展现有模块的功能非常有用。例如,在我们的房地产场景中,我们希望在常规用户视图中直接显示销售人员的财产列表.
在介绍特定的Odoo模块继承之前,让我们看看如何更改标准CRUD(创建、检索,更新或删除)方法的行为 。
目标
不能删除状态不为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方法 。
New
, Canceled
,则不让删除 提示:重写 unlink() ,并记住 self 可以是一个包含多条记录的结果集.
提示: 可在 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)
重启服务,刷新浏览器验证 。
删除非 New 、 Canceled 状态的房产,提示如下:
引用 : 查看主题相关文档 继承和扩展 。
我们希望在“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
: Field | Type |
---|---|
property_ids | One2many 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 # 本次新增
参考 : 主题关联文档可查看 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' # 本次新增
]
}
重启服务,验证效果 。
最后此篇关于odoo开发入门教程系列-继承(Inheritance)的文章就讲到这里了,如果你想了解更多关于odoo开发入门教程系列-继承(Inheritance)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我使用的是 PHP 5.3 稳定版,有时会遇到非常不一致的行为。据我所知,在继承中,父类(super class)中的所有属性和方法(私有(private)、公共(public)和 protected
所以我一直在努力寻找正确的方法来让应该非常简单的继承发挥作用(以我想要的方式 ;)),但我失败得很惨。考虑一下: class Parent { public String name = "Pare
给定这些类: class Father { public Father getMe() { return this; } } class Child extends Father {
为什么最后打印“I'm a Child Class”。 ? public class Parent { String parentString; public Parent()
我知道有很多类似的问题对此有很多很好的答案。我试着看看经典的继承方法,或者那些闭包方法等。不知何故,我认为它们对我来说或多或少是“hack”方法,因为它并不是 javascript 设计的真正目的。
我已经使用表单继承有一段时间了,但没有对以下方法进行太多研究。只需创建一个新类而不是表单并从现有表单继承并根据需要将所需控件转换为 protected 。 Visual Studio 2010 设计器
我原以为下面的代码片段会产生编译错误,因为派生类不会有我试图在 pub_fun() 中访问的 priv_var。但是它编译了,我得到了下面提到的输出。有人可以解释这背后的理论吗? class base
继承的替代方案有哪些? 最佳答案 Effective Java:优先考虑组合而不是继承。 (这实际上也来自《四人帮》)。 他提出的情况是,如果扩展类没有明确设计为继承,继承可能会导致许多不恰当的副作用
我有2个类别:动物( parent )和狗(动物的“ child ”),当我创建一个 Animal 对象并尝试提醒该动物的名称时,我得到了 undefined ,而不是她的真名。为什么?(抱歉重复发帖
我试图做继承,但没想到this.array会像静态成员一样。我怎样才能让它成为“ protected /公开的”: function A() { this.array = []; } func
在创建在父类中使用的 lambda 时,我试图访问子类方法和字段。代码更容易解释: class Parent { List> processors; private void do
如果我有一个对象,我想从“ super 对象”“继承”方法以确保一致性。它们将是混合变量。 修订 ParentObj = function() { var self = this; t
class Base { int x=1; void show() { System.out.println(x); } } class Chi
目前我正在尝试几种不同的 Javascript 继承方法。我有以下代码: (“借用”自 http://www.kevlindev.com/tutorials/javascript/inheritanc
我在 .popin-foto 元素中打开一个 popin。当我尝试在同一元素中打开子类 popin 时,它不起作用。 代码 这是 parent function Popin(container, ti
我有以下两个类: class MyClass { friend ostream& operatorvalue +=1; return *this; } 现在
有没有办法完全忽略导入到 html 文件中的 header 中的 CSS 文件? 我希望一个页面拥有自己独立的 CSS,而不是从任何其他 CSS 源继承。 最佳答案 您可以在本地样式表中使用 !imp
Douglas Crockford似乎喜欢下面的继承方式: if (typeof Object.create !== 'function') { Object.create = functio
假设我有以下代码: interface ISomeInterface { void DoSomething(); void A(); void B(); } public
class LinkedList{ public: int data; LinkedList *next; }; class NewLinkedList: public Lin
我是一名优秀的程序员,十分优秀!