Odoo中的繼承
轉載請註明原文地址:https://www.cnblogs.com/cnodoo/p/9280003.html
在實際開發過程中,經常會遇到需要修改Odoo原生邏輯的情況。然而,直接修改Odoo底層代碼,不利於後面odoo版本叠代時替換。因此,在不改變底層對象的時候添加新的功能,就顯得十分重要。
Odoo提供繼承機制來實現這個目的,繼承修改可以發生:Python代碼和XML視圖、Qweb模版上。
一:模型繼承
1:模型修改
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class Sub(models.Model):
_inherit = ‘Root‘ //通過_inherit屬性來繼承父模型
newCol=fields.XX.... //在下面添加新字段即可。
1)添加字段
如上,直接定義新字段即可。
2)修改現有字段
為了改變現有字段的屬性,只需再次定義該同名字段,需要修改的屬性顯式重寫即可,會保留未修改的所有其他未在此處明確使用的字段的屬性。
3)添加方法
添加新方法很簡單:只需在繼承類中聲明新的函數。
4)修改方法
擴展或更改現有邏輯,可以通過聲明具有完全相同名稱的方法來覆蓋相應的方法。
新方法將替換前一個方法,它可以只是擴展繼承類的代碼,使用Python的super()方法來調用父方法。然後,可以在調用super()
2:模型繼承的方式
1)類繼承
擴展類中沒有_name屬性,因為它繼承了父類的_name。對現有模型的擴展, 添加新功能,都將添加到現有模型中,不會創建新模型。 因此,在odoo中,根據_name唯一確定這個模型時找到的就是擴展後的類。(如上面添加字段是類繼承)
2)原型繼承(帶name繼承,創建新的表)
我們想使用具有不同於父模型的值的_name屬性,我們將獲得一個新模型重用來自繼承的特性,但是具有自己的數據庫表和數據。其實就是把繼承的類的功能特性拷貝給新的模型使用,並不改變被繼承模型。
復制意味著被繼承的方法和字段也將在繼承模型中可用。 對於字段,這意味著它們也將被創建並存儲在目標模型的數據庫表中。 原始(繼承)和新(繼承)模型的數據記錄保持不相關,只有定義是共享的。
3)代理繼承(委托繼承)【以成員變量的形式把父類對象包含進來】
使用_inherits屬性,它允許一個模型以透明的方式包含其他模型。通過字典映射繼承模型與字段的關系,並關聯它們。
通俗解釋:(相當於成員變量:引用一個外部的類對象賦值給這個模型的一個成員,但是對象的值是保存在被引用的類的數據庫表中的。但是在當前類通過成員修改了變量值,則會同步到被引用的類的數據庫表中)
優點是不需要在幾個表之間重復數據結構,例如地址。 任何需要包含地址的新模型都可以將其委派給嵌入式合作夥伴模型。 如果在合作夥伴地址字段中引入了修改,則這些修改會立即提供給嵌入它的所有模型!
二:視圖繼承
表單,列表和搜索視圖是使用arch XML結構定義的,要擴展視圖,我們需要一種方法來修改這個XML。 這意味著需要定位XML中的元素位置,然後在這些位置引入修改。
對於XML,在其中定位元素的最好方法是使用XPath表達式,如果XPath表達式匹配到多個元素,只有第一個元素會被修改。
因此,表達式應該使用獨特的屬性以使其指定盡可能具體,使用name屬性是確保我們找到擴展點的確切xml元素的最簡單方法。 因此,在我們的視圖XML元素上定義name屬性是很重要的。
Xpath表達式的格式:expr="//標簽名[@屬性]=‘屬性值‘" 意思是:找到 屬性=屬性值 的標簽的位置。
下面是一個寫在arch中的實現在is_done字段之前添加date_deadline字段的具體例子:
<xpath expr="//field[@name]=‘is_done‘" position="before"> //expr屬性值的意思是:找到<filed name="is_done"/>的標簽 <field name="date_deadline" /> </xpath>
Odoo為此提供了快捷符號,因此大多數時候我們可以完全避免XPath語法。 我們僅使用要定位的元素的特定屬性及定位類型相關信息就可以了。
<field name="is_done" position="before"> <field name="date_deadline" /> </field>
【如果字段在同一視圖中多次出現,則應始終使用XPath語法。】
position屬性是可選的:
after:將內容添加到父元素之中,匹配的節點之後。
before:添加內容在匹配節點之前。
inside(默認值):匹配節點內的追加內容。
replace:替換匹配的節點。如果使用空內容,它將刪除該匹配的元素。
attributes:修改匹配元素的XML屬性。在元素內容使用<attribute name =“attr-name”>實現給標簽設置新屬性值attr-name。
1)擴展表單視圖
<record id="view_form_模塊名_inherited" model="ir.ui.view">
<field name="name">模塊名_extension</field>
<field name="model">模塊.數據模型</field>
<field name="inherit_id" ref="模塊_模型.被繼承的form表單name屬性"/>
<field name="arch" type="xml"> //在arch中進行擴展操作:定位—>插入/修改
<field name="定位標簽位置" position="在標簽的哪裏進行擴展">
<field ......> //擴展內容
</field>
</field>
</record>
2)擴展列表視圖
<record id="view_tree_模型名_inherited" model="ir.ui.view">
<field name="name">模型名 extension</field>
<field name="model">模塊.模型</field>
<field name="inherit_id" ref="被繼承的tree視圖name名"/>
<field name="arch" type="xml">//在arch中進行擴展
<field name="定位標簽名" position="擴展位置">
<field ....進行擴展 />
</field>
</field>
</record>
3)擴展搜索視圖
<record id="view_filter_模型名_inherited" model="ir.ui.view">
<field name="name"> extension</field>
<field name="model">模型名</field>
<field name="inherit_id" ref="被繼承的filter視圖名"/>
<field name="arch" type="xml"> //下面進行定位、擴展舉例
<field name="name" position="after">
<filter name="filter_my_tasks" string="My Tasks" domain="[(‘user_id‘,‘in‘,[uid,False])]" />
</field>
</field>
</record>
4)修改記錄
對於記錄:
<record id="x" model="y">
數據記錄加載時,實際上對模型y執行了create或update操作︰ 如果記錄x不存在,則創建它; 否則,更新原來對應的值。
修改菜單項:
< ! — — 修改菜單項-->
<record id="菜單視圖id" model="ir.ui.menu">
//進行修改
</record>
修改action_window:
<record model="ir.actions.act_window"
id="action菜單id">
//進行修改
</record>
二:模塊數據
1:列表數據的導出
數據導出是tree視圖的標準功能,不涉及編碼。
只需在列表視圖左側復選框勾選需要導出的記錄,然後點擊列表上方“動作”下拉列表,選擇“導出”。
在導出對話框中選擇需要導出的列、導出的格式(一般選擇CSV,勾選 導入兼容導出),然後點擊“導出到文件”即可。
2:導入數據
在面板點擊“導入”按鈕,選擇文件後載入。然後點擊“驗證”,檢查文件內容的格式合法性,如果正常,則點擊“導入”即可。
3:模塊數據
模塊使用數據文件,將其配置加載到數據庫,可以通過CSV和XML文件完成。為了完整性,也可以使用YAML文件格式,但是它很少用於加載數據。
一個附加的限制是文件名必須與要加載數據的模型的名稱匹配,這樣系統才可以推斷應該將數據導入相應的模型。
數據CSV文件的常見用法是加載到ir.model.access模型中的安全定義。
4:演示數據
一個模塊在安裝時,盡量事先定義一些演示數據,方便在安裝後進行測試使用。
演示數據我們放在data目錄下,命名為 xx.xx.csv或者xx.xx.xml
然後在manifest文件中的data屬性進行配置。
5:XML
noupdate:重復數據加載時,將重寫上次運行中加載的記錄。 這意味著升級一個模塊將覆蓋在數據庫內可能已經進行的任何手動更改。此重新導入行為是默認值,但可以更改,以便在升級模塊時,某些數據文件記錄保持不變。 這是通過<odoo>或元素的noupdate =“1”屬性完成的。 這些記錄將在安裝addon模塊時創建,但在後續模塊升級中不會對其進行任何操作。
XML中定義記錄:
每個<record>元素有兩個基本屬性id和model,並且包含為每列分配值的<field>元素。如前所述,id屬性對應於記錄的外部標識符,並且模型屬性對應於要寫入記錄的目標模型。
設置字段值的幾種方式如下:
1:<record>元素定義數據記錄並包含<field>元素以設置每個字段的值,field元素的name屬性標識要寫入的字段,要寫入的值是元素內容:字段的開始和結束標記之間的文本。
2:定義字段值的更精細的替代方法是eval屬性:它評估一個Python表達式並將結果值分配給字段。
<field name="date_deadline" eval="(datetime.now() + timedelta(-1)).strftime(‘%Y-%m-%d‘)" />
3:<field>元素還有一個ref屬性,用於使用外部標識符設置many-to-one字段的值。
<field name="user_id" ref="base.user_demo" />
XML中觸發函數:
可以通過<function>元素,在其加載過程中執行方法。這可以用來建立演示和測試數據。
<function model="數據模型" name="數據模型中的方法" eval="參數" />
另一方式是觸發工作流:
<workflow model="模型" ref="工作流實例" action="工作流信號:觸發工作流" />
Odoo中的繼承