繼承(Inheritance)
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方法
- 如果房產記錄狀態不是
New,Canceled,則不讓洗掉
提示:重寫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)
重啟服務,重繪瀏覽器驗證
洗掉非New、Canceled狀態的房產,提示如下:



模塊繼承(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:
| 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 # 本次新增
視圖繼承(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' # 本次新增
]
}
重啟服務,驗證效果

作者:授客
微信/QQ:1033553122
全國軟體測驗QQ交流群:7156436
Git地址:https://gitee.com/ishouke
友情提示:限于時間倉促,文中可能存在錯誤,歡迎指正、評論!
作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額隨意,您的支持將是我繼續創作的源動力,打賞后如有任何疑問,請聯系我!!!
微信打賞
支付寶打賞 全國軟體測驗交流QQ群
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/550096.html
標籤:Python
下一篇:輕量級Web框架Flask(二)



