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, modelsclass TestModel(models.Model): _name = "test.model" _description = "Test Model" ...
我们的 TestModel
类继承与Model
,该Model
类提供了 create()
, read()
, write()
和unlink()
方法。
这些方法(和其它在Model
中定义的任何方法)可被扩展以添加指定业务逻辑:
from odoo import fields, modelsclass 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
中
元素的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, modelsclass 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, fieldsclass 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_typefrom . import estate_property_tagfrom . import estate_property_offerfrom . import estate_propertyfrom . import estate_res_user # 本次新增
视图继承(View Inheritance)参考: 主题关联文档可查看Inheritance.
目标: 在用户表单视图中显示与销售人员关联的avaliable房产列表其用户表单视图
Odoo提供了视图继承,其中子“扩展”视图应用于根视图之上,而不是就地修改现有视图(通过重写它们)。这些扩展既可以添加内容,也可以从父视图中删除内容。
扩展视图使用inherit_id
字段引用其父视图。它的arch
字段包含多个xpath
元素,用于选择和更改父视图的内容,而不是单个视图:
inherited.model.form.inherit.test inherited.model
expr
一个用于选择父视图中单个元素的XPath表达式。如果不匹配任何元素或者匹配多个元素,则抛出错误
position
应用于匹配元素的操作:
inside
将xpath
的主体附加到匹配元素的末尾(个人理解,添加为匹配元素的子元素)
replace
将匹配元素替换为xpath
的主体,将新主体中出现的任何$0
节点替换为原始元素
before
在匹配元素之前插入xpath
的主体作为同级元素
after
在匹配的元素之后插入xpaths
的主体,作为同级元素
attributes
使用xpath
主体中的特定属性元素更改匹配元素的属性
当匹配单个元素时,可以直接在要查找的元素上设置position
属性。以下两种继承都有相同的结果
在这里可以找到视图继承扩展的示例
account.move.form account.move
练习--添加字段到用户视图添加property_ids
字段到 base.view_users_form
中新建的notebook
页
提示: 可以在 这里找到继承用户视图的示例。
res.users.view.form.inherit.gamification res.users
新增odoo14\custom\estate\views\estate_res_users_views.xml
estate.res.users.view.form res.users
修改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" # 本次新增 ]}
重启服务,验证效果
-
艺术家边剃头,边作画,用10万根白发创造“新东方明珠”这是一幅发人深思的画作。近日,上海艺术家杨烨炘走出封闭2个月的家门,以行为绘画的方式创作了《新东方明珠图》献给上海。杨烨炘以疫情期
-
花8000多元买的商品,白等两个月却没收到货?亚马逊回应“花8000多元买的商品,白等了两个月却没收到货。”近日,消费者赵先生向《中国消费者报》投诉,称他通过亚马逊购物APP下了两笔订单,在等待两个月后订单均被强制取消。
-
广东省消委会发布二手车买卖合同示范文本为配合广东省推进“阳光二手车”工作,促进二手车流通行业健康发展,推动经营主体树立诚信经营理念,规范二手车交易行为,切实保护消费者的合法权益。
-
国家卫健委:家庭医生签约服务“最后一公里”有望打通3月15日,国家卫生健康委、财政部等六部门共同提出的《关于推进家庭医生签约服务高质量发展的指导意见》(以下简称《意见》)发布。
-
2022年1~2月房企拿地榜出炉:冠军碧桂园近日,中指研究院公布了2022年1~2月房企拿地(金额)TOP100榜单。令业内惊讶的是,除了品牌房企名次“乾坤大挪移”,榜单内还冒出了许多“名不见经传”的新面孔。
X 关闭
X 关闭