- 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的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我需要一些说明。我可以直接写入 /dev/port 以直接访问并行端口并且它工作正常(我可以打开插入端口连接器的 LED)。但是,我想我可以用 /dev/mem 做同样的事情? (http://tld
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我使用 Visual C++ 和 Win32 API 学习了 Windows 编程。如今,似乎大多数应用程序都是使用 C# 在 .NET 中开发的。我知道大多数时候 native 代码和托管代码之间没
请耐心等待。我正在制作一个 java 控制台,类似于此处找到的 DragonConsole https://code.google.com/p/dragonconsole/ 。一切都按计划进行,但我想
关闭。这个问题需要更多 focused .它目前不接受答案。 想要改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭5年前。 Improve this que
Django 的开发服务器表现得很奇怪。访问它的浏览器在加载时卡住,任何退出它的尝试都不起作用。当我点击 control c看似相当,但实际上仍在运行。让它退出的唯一方法是重新启动我的电脑,这很令人沮
我正在使用 Flash Develop,并且创建了一个 ActionScript 3.0 项目。它启动并读取一个 xml 文件,其中包含图像的 url。我已将 url 保留在与 swf 相同的文件夹中
是否可以根据其 website 上提供的规范开发 AUTOSAR BSW 堆栈(例如用于 CAN 通信)?不购买任何昂贵的供应商工具?可以遵循哪些步骤?我被要求探索这种可能性。 最佳答案 是和否。工具
有人知道如何用音频文件的内容覆盖 iPhone 麦克风吗? 想象一个场景,您正在通话,并且想要播放一些简短的音频让其他人听到。 因此,有必要将麦克风(硬件)置于保持状态,并使用委托(delegate)
我遇到了这个问题,我的应用程序出现 EXC_BAD_ACCESS 错误并卡住/停止。我使用模拟器的“向左旋转”和“向右旋转”选项来模拟方向变化行为。导致此错误的可能原因有哪些?由于我没有获得有关错误的
我有超过 1 台 Mac,我想在所有这些 Mac 上进行开发。我知道我需要在每台机器上同步我的手机,但这是我遇到的最小的问题。看起来我无法在手机上运行应用程序,除了在其中之一上开发的应用程序。 是否有
在手机上测试时,我的应用程序在特定点崩溃。控制台显示此消息 Tue Jan 27 15:47:14 unknown SpringBoard[22] : Application com.myprof.
我有一个案例,我从服务器获取信息。我的应用程序有一个选项卡栏和导航按钮。我希望应用程序显示进度指示器并禁用所有其他控件,以便用户在从服务器提取数据时无法跳转。我怎样才能实现这个目标? 我想到的一种方法
有时,当我尝试“构建”/编译下载的源代码时,我会收到以下警告: ld: warning: directory '/Volumes/Skiiing2/CD/ViewBased/Unknown Path/
我无法在 Apple 文档中找到关于开发和分发配置之间差异的明确解释。我目前正在使用开发配置在我的 iPhone 上进行开发和测试。我打算将该应用程序分发到我的 Beta 测试中,我想知道: 我需要使
我在使用 SharePoint 时遇到的最大挑战之一是它不能很好地适应典型的项目环境,其中至少包含开发和生产环境。我遇到的最多的问题是内容和列表是如此紧密地耦合在一起,以至于如果不在生产环境中执行内容
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
首先,我告诉你-我是编码新手 我正在使用vs代码来学习c++,它不会产生像dev c++或codeblocks这样的调试器。我看了一些视频,其中我们必须编辑json文件,这对于初学者来说非常复杂。有人
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
我开发了一个 Ionic 应用程序(iOS 和 Android 的混合)。我有 Xcode 8.3.3 并购买了一年的 Apple Developer Program 订阅。 我不想测试我的应用并将其
我是一名优秀的程序员,十分优秀!