繼承(Inheritance)
Odoo的一個(gè)強(qiáng)大方面是它的模塊化。模塊專用于業(yè)務(wù)需求,但模塊也可以相互交互。這對于擴(kuò)展現(xiàn)有模塊的功能非常有用。例如,在我們的房地產(chǎn)場景中,我們希望在常規(guī)用戶視圖中直接顯示銷售人員的財(cái)產(chǎn)列表。
在介紹特定的Odoo模塊繼承之前,讓我們看看如何更改標(biāo)準(zhǔn)CRUD(創(chuàng)建、檢索,更新或刪除)方法的行為
Python繼承(Python Inheritance)
目標(biāo):
不能刪除狀態(tài)不為New、Canceled的房產(chǎn)
預(yù)期效果動畫地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/unlink.gif
房產(chǎn)收到報(bào)價(jià)時(shí),房產(chǎn)狀態(tài)應(yīng)該改成‘Offer Received’
不能以低于現(xiàn)有報(bào)價(jià)的價(jià)格創(chuàng)建報(bào)價(jià)
預(yù)期效果動畫地址:https://www.odoo.com/documentation/14.0/zh_CN/_images/create.gif
在我們的房地產(chǎn)模塊中,我們從不需要開發(fā)任何特定的東西來執(zhí)行標(biāo)準(zhǔn)的CRUD操作。Odoo框架提供了實(shí)現(xiàn)這些操作的必要工具。事實(shí)上,多虧經(jīng)典的Python繼承,我們的模型中已經(jīng)包含了這樣的操作:
from odoo import fields, models
class TestModel(models.Model):
_name = "test.model"
_description = "Test Model"
...
我們的 TestModel
類繼承與Model
,該Model
類提供了 create()
, read()
, write()
和unlink()
方法。
這些方法(和其它在Model
中定義的任何方法)可被擴(kuò)展以添加指定業(yè)務(wù)邏輯:
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()
方法來說是必需的,因?yàn)榻Y(jié)果集self
的內(nèi)容和創(chuàng)建(creation)的上下文無關(guān),但該裝飾器對于其它CRUD方法來說不是必需的。
Python 3中, super()
等價(jià)于 super(TestModel, self)
。當(dāng)你需要使用一條被修改后的結(jié)果集調(diào)用父方法時(shí),可能需要使用后者。
危險(xiǎn)提示
- 總是調(diào)用
super()
以避免中斷流非常重要。只有少數(shù)非常特殊的情況才無需調(diào)用它。- 總是返回和父方法一致的數(shù)據(jù)。例如父方法返回一個(gè)
dict()
,你重寫父方法時(shí)也要返回一個(gè)dict()
練習(xí)--添加業(yè)務(wù)邏輯到CRUD方法
- 如果房產(chǎn)記錄狀態(tài)不是
New
,Canceled
,則不讓刪除
提示:重寫unlink()
,并記住self
可以是一個(gè)包含多條記錄的結(jié)果集。
- 創(chuàng)建報(bào)價(jià)時(shí),設(shè)置房產(chǎn)狀態(tài)為‘Offer Received’,如果用戶試圖以低于已存在報(bào)價(jià)的金額創(chuàng)建報(bào)價(jià)時(shí)拋出錯(cuò)誤。
提示: 可在vals
中獲取property_id
字段,但是它是一個(gè)int
型。要實(shí)例化一個(gè)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"
屬性(說明:為了方便執(zhí)行報(bào)價(jià)創(chuàng)建操作)
修改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
說明:為了方便實(shí)踐操作,暫且不做售價(jià)校驗(yàn)
最末尾新增以下代碼
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
,導(dǎo)入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('不能低于現(xiàn)有報(bào)價(jià)')
property.state = 'Offer Received'
return super().create(vals)
重啟服務(wù),刷新瀏覽器驗(yàn)證
刪除非New
、Canceled
狀態(tài)的房產(chǎn),提示如下:
模塊繼承(Model Inheritance)
引用: 查看主題相關(guān)文檔繼承和擴(kuò)展
我們希望在“Settings/Users & Companies/Users”表單視圖中直接顯示與銷售人員關(guān)聯(lián)的房產(chǎn)列表。為此,我們需要向res.users
模型添加一個(gè)字段,并調(diào)整其視圖以顯示它。
Odoo提供了兩種繼承機(jī)制來以模塊化的方式擴(kuò)展現(xiàn)有模型。
第一繼承機(jī)制允許模塊通過以下方式修改在另一個(gè)模塊中定義的模型的行為:
-
向模型添加字段
-
覆蓋模型中字段的定義
-
給模型添加約束
-
給模型添加方法
-
重寫模型中的現(xiàn)有方法
第二種繼承機(jī)制(委托)允許將模型的每個(gè)記錄鏈接到父模型的記錄,并提供對該父記錄的字段的透明訪問。
odoo中,第一種機(jī)制最常用。在我們的例子中,我們希望向現(xiàn)有模型添加一個(gè)字段,這意味著我們將使用第一種機(jī)制。例如:
from odoo import fields, models
class InheritedModel(models.Model):
_inherit = "inherited.model"
new_field = fields.Char(string="New Field")
這里可以找到將兩個(gè)字段添加到模型中的示例
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
按照慣例,每個(gè)繼承的模型都在其自己的Python文件中定義。在我們的示例中為“models/inherited_model.py”。
練習(xí)--添加字段到用戶模型
- 添加一下字段到
res.users
:
Field | Type |
---|---|
property_ids | One2many inverse of salesman_id to estate.property
|
- 添加一個(gè)
domain
到該字段,這樣以便僅顯示可獲取房產(chǎn)。
新增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)
參考: 主題關(guān)聯(lián)文檔可查看Inheritance.
目標(biāo): 在用戶表單視圖中顯示與銷售人員關(guān)聯(lián)的avaliable房產(chǎn)列表其用戶表單視圖
Odoo提供了視圖繼承,其中子“擴(kuò)展”視圖應(yīng)用于根視圖之上,而不是就地修改現(xiàn)有視圖(通過重寫它們)。這些擴(kuò)展既可以添加內(nèi)容,也可以從父視圖中刪除內(nèi)容。
擴(kuò)展視圖使用inherit_id
字段引用其父視圖。它的arch
字段包含多個(gè)xpath
元素,用于選擇和更改父視圖的內(nèi)容,而不是單個(gè)視圖:
<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="http://field[@name='description']" position="after">
<field name="new_field"/>
</xpath>
</field>
</record>
-
expr
一個(gè)用于選擇父視圖中單個(gè)元素的XPath表達(dá)式。如果不匹配任何元素或者匹配多個(gè)元素,則拋出錯(cuò)誤
-
position
應(yīng)用于匹配元素的操作:
inside
將
xpath
的主體附加到匹配元素的末尾(個(gè)人理解,添加為匹配元素的子元素)replace
將匹配元素替換為
xpath
的主體,將新主體中出現(xiàn)的任何$0
節(jié)點(diǎn)替換為原始元素before
在匹配元素之前插入
xpath
的主體作為同級元素after
在匹配的元素之后插入
xpaths
的主體,作為同級元素attributes
使用
xpath
主體中的特定屬性元素更改匹配元素的屬性
當(dāng)匹配單個(gè)元素時(shí),可以直接在要查找的元素上設(shè)置position
屬性。以下兩種繼承都有相同的結(jié)果
<xpath expr="http://field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
在這里可以找到視圖繼承擴(kuò)展的示例
<?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="http://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="http://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>
練習(xí)--添加字段到用戶視圖
添加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="http://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' # 本次新增
]
}
重啟服務(wù),驗(yàn)證效果文章來源:http://www.zghlxwxcb.cn/news/detail-413421.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-413421.html
到了這里,關(guān)于odoo 開發(fā)入門教程系列-繼承(Inheritance)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!