環境 odoo-14.0.post20221212.tar ORM API學習總結/學習教程 模型(Model) Model欄位被定義為model自身的屬性 from odoo import models, fields class AModel(models.Model): _name = 'a. ...
環境
odoo-14.0.post20221212.tar
ORM API學習總結/學習教程
模型(Model)
Model欄位被定義為model自身的屬性
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
警告
欄位的名稱和方法的名稱不能相同,最後定義的方法、函數名稱會覆蓋前面定義的相同名稱。
預設的,欄位的標簽(Lable,即用戶可見欄位名稱)為對應欄位名稱開頭字母改成大寫後的值,可通過 string
欄位屬性改成修改欄位Label
field2 = fields.Integer(string="Field Label")
可通過default
,定義預設值:
name = fields.Char(default="a value")
預設值也可以通過函數獲取:
def _default_name(self):
return 'Title'
name = fields.Char(default=lambda self: self._default_name())
API
BaseModel
class odoo.models.BaseModel
[源代碼]
Odoo模型的基類。Odoo mode可通過繼承一下類來創建Model:
Model
用於常規資料庫持久化模型TransientModel
用於臨時數據,存儲在資料庫中,但每隔一段時間就會自動清空AbstractModel
用於多繼承模塊共用的抽象父類,不會在資料庫中創建模型表
系統為每個資料庫自動實例化每個模型一次。這些實例表示每個資料庫上的可用模型,取決於該資料庫上安裝的模塊。每個實例的實際類都是從創建和繼承相應模型的Python類構建的。
每個模型實例都是一個“記錄集(recordset)”,即模型記錄的有序集合。記錄集由 browse()
, search()
或欄位訪問等方法返回。記錄沒有顯式的表示:單條記錄表示為一條記錄的記錄集。
要創建不需要實例化的類,可以將 _register
屬性設置為False
-
_auto= False
是否應該創建資料庫表。如果設置為
False
, 應該重寫init()
來創建資料庫表。預設設。針對Model
和TransientModel
自動設置為False
,針對AbstractModel
自動設置為False
。可通過繼承AbstractModel
來創建不需要任何數據表的模型 -
_log_access
ORM是否自動生成和更新 Access Log fields。預設
_auto
的值。 -
_table= None
模型對應的資料庫表的名稱。如果
_auto
設置為True
的話。 -
_sequence= None
用於ID欄位的SQL序列
-
_sql_constraints= []
sql約束,格式:
[(name, sql_def, message)]
-
_register= True
registry visibility
-
_abstract= True
是否為抽象模型
-
_transient= False
是否為transient模型
-
_name= None
模型名稱(以 點分式命名的模塊名稱,比如
estate.users
) -
_description= None
模塊描述,非整數名稱
-
_inherit= None
繼承的Python模型:需要繼承模型的名稱(
_name
屬性值)或者名稱列表(list
類型) -
_inherits= {}
(不太理解)dictionary {‘parent_model’: ‘m2o_field’} mapping the _name of the parent business objects to the names of the corresponding foreign key fields to use:
_inherits = { 'a.model': 'a_field_id', 'b.model': 'b_field_id' }
implements composition-based inheritance: the new model exposes all the fields of the inherited models but stores none of them: the values themselves remain stored on the linked record.
警告
if multiple fields with the same name are defined in the
_inherits
-ed models, the inherited field will correspond to the last one (in the inherits list order). -
_rec_name= None
用於標記記錄的欄位,預設值:
name
-
_order= 'id'
用於搜索結果的預設排序欄位
-
_check_company_auto= False
執行
write
和create
, 對擁有check_company=True
屬性的關聯欄位調用_check_company
以確保公司一致性 -
_parent_name= 'parent_id'
用作父欄位的many2one欄位
-
_parent_store= False
設置為
True
以計算parent_path
欄位。與parent_path
欄位一起,設置記錄樹結構的索引存儲,以便使用child_of
和parent_of
域運算符對當前模型的記錄進行更快的分層查詢 -
_date_name= 'date'
用於預設日曆視圖的欄位
-
_fold_name= 'fold'
用於確定看板視圖中摺疊組的欄位
AbstractModel
odoo.models.AbstractModel
[源代碼]
odoo.models.BaseModel
的別名
Model
class odoo.models.Model
[源代碼]
常規資料庫持久化Odoo模型的主要父類。
通過繼承此類來創建Odoo模型的:
class user(Model):
...
系統將為安裝了該類模塊的每個資料庫實例化一次類
-
_auto= True
是否應該創建資料庫表。如果設置為
False
, 應該重寫init()
來創建資料庫表。預設設。針對Model
和TransientModel
自動設置為False
,針對AbstractModel
自動設置為False
。可通過繼承AbstractModel
來創建不需要任何數據表的模型 -
_abstract= False
是否為抽象模型
-
_transient= False
是否為transient模型
TransientModel
class odoo.models.TransientModel
[源代碼]
用於臨時記錄的父類模型,旨在暫時保持,並定期進行清理
TransientModel
具有簡化的訪問許可權管理,所有用戶都可以創建新記錄,並且只能訪問他們創建的記錄。超級用戶可以無限制地訪問所有TransientModel
記錄。
-
_auto= True
是否應該創建資料庫表。如果設置為
False
, 應該重寫init()
來創建資料庫表。預設設。針對Model
和TransientModel
自動設置為False
,針對AbstractModel
自動設置為False
。可通過繼承AbstractModel
來創建不需要任何數據表的模型 -
_abstract= False
是否為抽象模型
-
_transient= False
是否為transient模型
欄位(Fields)
class odoo.fields.Field[源代碼]
欄位擁有以下屬性
-
string (str) – 用戶看到的欄位的標簽;如果未設置,ORM將採用類中的欄位名開頭字母改成大寫後的
-
help (str) – 用戶看到的欄位的提示條(設置該屬性後,當滑鼠懸停在欄位標簽上方時,會自動浮現提示條,顯示該屬性的文字內容)。
-
invisible – 欄位是否可見。預設為
False
,即可見 -
readonly (bool) – 欄位在用戶界面是否只讀,預設值
False
,僅對UI起作用 -
required (bool) – 欄位在用戶界面是否必填,預設
False
。這通過在資料庫層面為列添加NOT NULL
約束來實現 -
index (bool) – 是否為欄位添加索引。註意:對不存儲、虛擬欄位不起作用。預設值:
False
-
default (值或者可調用對象) – 設置欄位的預設值。可以是靜態值,或者以結果集為入參,返回某個值的函數。使用
default=None
捨棄該欄位的預設值。 -
states (dict) –將
state
值映射到UI屬性-值對列表的字典映射,簡單說就是允許用戶界面依據state
欄位的值來動態設置對應欄位的UI屬性,因此,它要求存在一個state
欄位併在視圖中使用(即使是隱藏的),state
屬性的名稱是在odoo硬編碼且不允許修改的,可用屬性有:readonly
,required
,invisible
。例如states={'done':[('readonly',True)]}
,表示當state
值為done
時,將用戶界面states
所在欄位在設置為只讀(僅針對UI層面)用法舉例:
state = fields.Selection([ ('draft', 'To Submit'), ('cancel', 'Cancelled'), ('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved') ], string='Status', readonly=True, copy=False, default='confirm') date_from = fields.Datetime( 'Start Date', readonly=True, index=True, copy=False, states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
-
groups (str) – 值為逗號分隔的組XML ID列表,如
groups='base.group_user,base.group_system'
,可限制欄位只能被給定組用戶訪問。 -
company_dependent (bool) –
欄位值是否依賴於當前公司,如果設置為
True
,則表示依賴當前公司,即欄位值和公司綁定。這個屬性的作用就是讓同一欄位,可以根據不同公司,存儲不同的值,假設一個用戶屬於多個公司,他在不同公司的職務也不一樣,此時就可以設置該屬性為True
。該值未存儲在當前模型表中。它註冊為
ir.property
,也就是說它的值存儲在ir_property
表中,通過查詢該表來獲取該欄位的值。 -
copy (bool) – 當記錄重覆時,該欄位值是否被拷貝(在使用 ORM
copy()
方法複製並生成新記錄時,不複製該欄位的值)。 (針對普通欄位,預設值為:True
,針對one2many
和計算欄位,包括屬性欄位(property fields
,個人理解註冊ir.property
的欄位)和關係欄位,預設值為False
-
store (bool) – 該欄位是否存儲到資料庫,針對計算欄位,預設值為
False
,其它欄位預設為True
-
group_operator (str) –
在當前欄位上分組時,供
read_group()
使用的聚合函數支持的聚合函數:
array_agg
: 值,包括空值,連接成一個數組count
: 記錄數count_distinct
: 不重覆記錄數bool_and
: 如果所有值都為真,則為真,否則為假bool_or
: 如果至少有一個值為真,則為真,否則為假max
: 所有值的最大值min
: 所有值的最小值avg
:所有值的平均值(算術平均值)sum
: 所有值的總和
-
group_expand (str) –
用於在當前欄位上分組時用於擴展
read_group
結果的函數@api.model def _read_group_selection_field(self, values, domain, order): return ['choice1', 'choice2', ...] # available selection choices. @api.model def _read_group_many2one_field(self, records, domain, order): return records + self.search([custom_domain])
基礎欄位
class odoo.fields.Boolean[源代碼]
bool
的封裝
class odoo.fields.Char[源代碼]
基本字元串欄位,長度有限,通常在客戶端顯示為單行字元串
參數:
-
size(int) – 為該欄位可存儲最大值
-
trim(bool) – 說明該值是否被修剪(預設情況下,
True
)。請註意,修剪操作僅由 Web 客戶端應用。 -
translate(bool 或者可調用對象)
– 啟用欄位值的翻譯;用於
translate=True整體翻譯欄位值;
translate也可以是可調用的,從而使得
translate(callback,value)通過使用
callback(term)來檢索術語的翻譯來翻譯
value`
class odoo.fields.Float[源代碼]
float
的封裝
精度數字由可選的digitals
屬性給出。
參數
-
digits (
tuple
(int
,int
), 或者str
) – 一個元組(total, decimal)
或者引用DecimalPrecision
記錄的字元串digits=(8,2) 表示總的8位,小數點占2位
Float類為此提供了一些靜態方法:
round()
以給定精度對浮點值進行舍入。is_zero()
檢查浮點值在給定精度下是否等於零。compare()
按給定精度比較兩個浮點值。
例子:
fields.Float.round(self.product_uom_qty, precision_rounding=self.product_uom_id.rounding)
fields.Float.is_zero(self.product_uom_qty, precision_rounding=self.product_uom_id.rounding)
field.Float.compare(self.product_uom_qty, self.qty_done, precision_rounding=self.product_uom_id.rounding)
比較助手出於歷史目的使用__cmp_
語義,因此使用此助手的正確慣用方式如下:
如果result==0,則第一個和第二個浮點數相等,如果result<0,第一個浮點數小於第二個,如果result>0,第一個浮動點數大於第二個浮動點數
class odoo.fields.Integer[源代碼]
int
的封裝
高級欄位
class odoo.fields.Binary[源代碼]
封裝二進位內容(比如一個文件)。
參數:
- attachment(bool)
– 欄位是否存儲為
ir_attachment還是該model表的一列(預設為:
True`,即存儲為前者。
class odoo.fields.Html[源代碼]
html代碼內容的封裝
參數:略
class odoo.fields.Image[源代碼]
圖片的封裝,擴展Binary
如果圖像大小大於像素的max_width/max_height
限制,則通過保持縱橫比將圖像大小調整到該限制。
參數:
-
max_width(int ) – 圖像的最大寬度(預設值:
0
,無限制) -
max_height ( int) – 圖像的最大高度(預設值:
0
,無限制) -
verify_resolution ( bool) – 是否應驗證圖像解析度以確保它不會超過最大圖像解析度(預設值:
True
。最大圖像解析度請參閱odoo.tools.image.ImageProcess
(預設值:50e6
)。參數
如果沒有指定 max_width
/max_height
或者設置為0,且verify_resolution
為False
,則不會驗證欄位內容,此時應該使用Binary
欄位。
class odoo.fields.Monetary[源代碼]
封裝以給定res_currency
表示的浮點值。
小數精度和貨幣符號取自currency_field
屬性。
參數:
- currency_field (str) –擁有表示該貨幣欄位的
res_currency
的Many2one
欄位名稱(預設:'currency_id'
)
class odoo.fields.Selection[源代碼]
封裝不同值之間的互斥選擇。
說明:Selection
欄位的可選值,存儲在public.ir_model_fields_selection
表中,通過field_id
欄位通過public.ir_model_fields
表進行
-- 查詢Selection欄位ID
SELECT id FROM public.ir_model_fields
where model = 'stock.quality' and name='state'
-- 查詢Selection欄位可選值
select * from public.ir_model_fields_selection where field_id = 13028; -- 13028為Selection欄位ID
參數:
-
selection (list(tuple(str, str)) 或者可調用對象 或者 str)) – 指定欄位的可選值。其值為包含2元組的列表,或者返回前者模型方法,或者方法名稱
-
selection_add (list(tuple(str, str)) –
在重寫欄位的情況下,提供
selection
的擴展。它是一個包含二元組(value, label)
或者單元組(value,)
的列表,其中,單元組中的value
必須作為value
出現在selection
列表中的元組中。新值插入順序和原有selection
中元組順序保持一致:selection = [('a', 'A'), ('b', 'B')] selection_add = [('c', 'C'), ('b',)] > result = [('a', 'A'), ('c', 'C'), ('b', 'B')]
-
ondelete –
為帶有
selection_add
的任何重寫欄位提供回退機制。這是一個將selection_add
中的每個選項映射到回退操作的dict。此回退操作將應用於其
selection_add
選項映射到該操作的所有記錄。這些操作可以是以下任一操作:
set null
預設情況下,具有此選項的所有記錄的選擇值都將設置為False。cascade
–具有此選項的所有記錄將與選項本身一起刪除。set default
-具有此選項的所有記錄都將設置為欄位定義的預設值<callable>
-一個可調用對象,其第一個也是唯一的參數將是包含指定的Selection選項的記錄集,用於自定義處理
selection
屬性選擇是強制性的,除非是related
或擴展的欄位
class odoo.fields.Text[源代碼]
類似Char
,用於更長的內容,沒有大小,通常展示為多行文本框。
參數:
translate (bool 或者可調用對象) – 同 Char
Date(time) 欄位
當將一個值賦值給 Date
/Datetime
欄位時,以下選擇是合法的:
date
或datetime
對象.- 正確格式的字元:
Date
欄位採用YYYY-MM-DD
Datetime
欄位採用YYYY-MM-DD HH:MM:SS
False
或者None
.
Date
和Datetime
欄位類擁有以下輔助函數,用於嘗試轉換為相容類型:
to_date()
轉換為datetime.date
to_datetime()
轉換為datetime.datetime
.
示例
解析來自外部的日期/日期時間:
fields.Date.to_date(self._context.get('date_from'))
Date
/Datetime
比較最佳實踐:
Date
欄位只能和date對象比較Datetime
欄位只能和datetime對象比較
Datetime
欄位在資料庫中存儲為不帶時區的時間戳,並以UTC時區存儲。因為這樣可使Odoo資料庫獨立於托管伺服器系統的時區。時區轉換完全由客戶端管理。
Common operations with dates and datetimes such as addition, subtraction or fetching the start/end of a period are exposed through both Date
and Datetime
. These helpers are also available by importing odoo.tools.date_utils
.
class odoo.fields.Date源代碼
Python date
對象的封裝
-
static add(value, *args, **kwargs)
返回
value
和relativedelta
之和-
參數
value – 初始
date
或datetime
args – 傳遞給
relativedelta
的位置參數kwargs – 傳遞給
relativedelta
的關鍵詞參數 -
返回
date/datetime結果對象
示例:
from odoo.fields import Date print(Date.add(datetime.now(), years=1)) # 輸出形如:2024-01-03 # 常見參數: # years, months, days, leapdays, weeks, hours, minutes, seconds, microseconds
-
-
static subtract(value, *args, **kwargs)
[源代碼]返回
value
和relativedelta
之差-
參數
value – 初始
date
或者datetime
args – 傳遞給
relativedelta
位置參數kwargs – 傳遞給
relativedelta
的關鍵詞參數 -
返回
date/datetime
結果對象
-
-
static context_today(record, timestamp=None)
[源代碼]按客戶端時區以適合
date
欄位的格式返回當前日期註解
該方法可能用於計算預設值
-
參數
record – 從中獲取時區的記錄集
timestamp (
datetime
) – 替代當前日期時間(datetime)的可選的datetime
對象 -
返回類型
date
-
-
static end_of(value, granularity)
[源代碼]從日期或日期時間獲取時間段的結束
-
參數
value – 初始
date
或datetime
granularity – 字元串表示的時間段類型, 可以是
year
,quarter
,month
,week
,day
或者hour
。 -
返回
與指定時段的起始對應的
date/datetime
對象
示例:
print(datetime.now()) # 2023-01-03 10:12:32.332208 print(Date.end_of(datetime.now(), 'year')) # 輸出形如:2023-12-31 23:59:59.999999 print(Date.end_of(datetime.now(), 'month')) # 輸出形如:2023-01-31 23:59:59.999999
-
-
static start_of(value, granularity)
[源代碼]從日期或日期時間獲取時間段的開始
-
參數
value – 初始
date
或datetime
granularity – 字元串表示的時間段類型, 可以是
year
,quarter
,month
,week
,day
或者hour
。 -
返回
與指定時段的起始對應的
date/datetime
對象
示例:
print(datetime.now()) # 2023-01-03 10:18:57.071276 print(Date.start_of(datetime.now(), 'year')) # 輸出形如:2023-01-01 00:00:00 print(Date.start_of(datetime.now(), 'month')) # 輸出形如:2023-01-01 00:00:00 print(Date.start_of(datetime.now(), 'hour')) # 輸出形如:2023-01-03 10:00:00
-
-
static to_date(value)
[源代碼]嘗試轉換
value
為date
對象警告
如果value為
datetime
對象,它將被轉換為date
對象,且所有日期時間特定信息(HMS, TZ, …)都會丟失。-
參數
value (str 或 date 或 datetime) –需要轉換的值
-
返回
代表
value
的對象 -
返回類型
date
類型或者None
-
-
static to_string(value)
[源代碼]將
date
或者datetime
對象轉為字元串-
參數
value – 需要轉換的日期或者日期時間對象
-
返回
以伺服器日期格式返回代表
value
的字元串。如果value
為datetime
類型,自動捨棄小時,分,秒,時區信息。 -
返回類型:str
示例:
print(Date.to_string(datetime.now())) # 輸出形如:2023-01-03
-
-
static today(*args)
[源代碼]返回當前日期
示例:
print(Date.today()) # 格式形如:2023-01-03
class odoo.fields.Datetime[源代碼]
Python datetime
對象的封裝
-
static context_timestamp(record, timestamp)
[源代碼]返迴轉換為客戶端時區的給定時間戳。
註解
此方法不是用作預設初始值設定項,因為
datetime
欄位在客戶端顯示時會自動轉換。對於預設值,應使用now()
-
參數
record – 從中獲取時區的記錄集。
timestamp (datetime) – 待轉換為客戶端時區的naive
datetime
值 (UTC
表示的) -
返回
按上下文時區轉換為時區敏感的
datetime
-
返回類型
datetime
-
-
static add(value, *args, **kwargs)
[源代碼]參考
Date.add
-
static subtract(value, *args, **kwargs)
[源代碼]參考
Date.subtract
-
static end_of(value, granularity)
[源代碼]參考
Date.end_of
-
static start_of(value, granularity)
[源代碼]參考
Date.start_of
-
static to_string(value)
[源代碼]參考
Date.to_string
-
static today(args)
[源代碼]返回當天,午夜 (00:00:00)
示例:
from odoo.fields import Datetime print(Datetime.today()) # 輸出形如:2023-01-03 00:00:00 print(Datetime.now()) # 輸出當前時間 2023-01-03 12:33:00
-
static to_datetime(value)
[源代碼]將ORM
value
轉為datetime
值-
參數
value (str 或者 date 或者 datetime) – 需要轉換的值
-
返回
代表
value
的對象 -
返回類型
datetime
或者None
-
關係欄位(Relational Fields)
class odoo.fields.Many2one
[源代碼]
Many2one
欄位的值是大小為0(無記錄)或1(單個記錄)的記錄集。
參數:
- comodel_name (str) – 目標模型的名稱,
comodel_name
是必選參數,除非是相關或擴展欄位(不太理解,原文:name of the target modelMandatory
except for related or extended fields) - domain – 用於設置客戶端側候選值的可選 domain (domain 或者字元串)
- context (dict) – 處理該欄位時供客戶端使用的上下文
- ondelete (str) – 當引用的記錄被刪除時,怎麼處理:可選值有:
'set null'
,'restrict'
,'cascade'
- auto_join (bool) – 是否在搜索該欄位時生成
JOIN
(預設:False
) - delegate (bool) – 將其設置為
True
以標記可通過當前模型訪問目標模型的欄位(對應_inherits
) - check_company (bool) – 標記需要在
_check_company()
中校驗的欄位。取決於欄位屬性,添加一個預設的公司domain
class odoo.fields.One2many
[源代碼]
One2many
欄位的值為 comodel_name
中所有滿足條件的記錄的結果集,而目標模型中的 inverse_name
則等價於當前記錄。
參數:
- comodel_name (str) – 目標模型的名稱
- inverse_name (str) – 目標模型中反向
Many2one
欄位名稱,根據該欄位反向查詢記錄 - domain – 用於設置客戶端候選值的條件 (domain 或者字元串),可選
- context (dict) – 處理該欄位時供客戶端使用的上下文
- auto_join (bool) – 是否在搜索該欄位時生成
JOIN
(預設:False
) - limit (int) – 讀取時用的可選限制
comodel_name
和inverse_name
參數是必選參數,除非是相關或者擴展欄位
class odoo.fields.Many2many
[源代碼]
Many2many
欄位的值為一個結果集。
參數:
- comodel_name – 目標模型的名稱,必選參數,除非是關聯或者擴展欄位
- relation (str) – 資料庫中存儲關係的表名,可選參數。
- column1 (str) –
relation
表中引用"這些"記錄的列名,可選參數 - column2 (str) –
relation
表中引用"那些"記錄的列名,可選參數
relation
, column1
和column2
參數可選。 如果未給定,自動根據模型名稱生成,提供的不同的model_name
和comodel_name
。
註意,ORM不支持在給定模型,使用同樣的comodel
,創建多個省略了relation
參數的欄位,因為這些欄位將使用相同的表。ORM阻止兩個Many2many
欄位使用相同的relation
參數,除非:
- 兩個欄位都使用相同的模型,
comodel
並顯示指定relation
參數,否則 - 至少有一個欄位屬於攜帶
_auto = False
的模型
參數:
- domain – 用於設置客戶端候選值的條件 (domain 或者字元串),可選
- context (dict) – 處理該欄位時供客戶端使用的上下文
- check_company (bool) – 標記需要在
_check_company()
中校驗的欄位。取決於欄位屬性,添加一個預設的公司條件 - limit (int) – 讀取時用的可選限制
註意:odoo不會在當前模型對應表中為One2many
,Many2many
類型的屬性建立對應的表欄位,但會為Many2one
類型的屬性建立對應表欄位,針對Many2many
類型的屬性,odoo會建立一張輔助表,表名預設格式為model1_table_name_model2_table_name_rel
,該表擁有兩列,一列為當前模型表主鍵ID(model1_table_name_id
),一列為關係欄位關聯模型表的主鍵ID(model2_table_name_id
),這樣通過兩表記錄ID就可以查詢所需記錄了
偽關係欄位
-
class odoo.fields.Reference
[源代碼]偽關係欄位(資料庫中沒有FK)。該欄位值存儲為資料庫中遵循模式
"res_model,res_id"
的字元串。 -
class odoo.fields.Many2oneReference
[源代碼]該欄位的值存儲為資料庫中的一個整數。與
odoo.fields.Reference
欄位相反,必須在Char
類型欄位中指定模型,其中,該欄位的名稱必須在當前Many2oneReference
欄位中的model_field
屬性中指定參數:model_field (str) – 存儲模型的欄位名稱。
計算欄位
可以使用 compute
參數計算欄位(而不是直接從資料庫中讀取)它必須將計算值分配給欄位。如果它使用其他欄位的值,則應使用depends()
指定這些欄位
from odoo import api
total = fields.Float(compute='_compute_total')
@api.depends('value', 'tax')
def _compute_total(self):
for record in self:
record.total = record.value + record.value * record.tax
-
當使用子欄位時,依賴可使用分點路徑:
@api.depends('line_ids.value') def _compute_total(self): for record in self: record.total = sum(line.value for line in record.line_ids)
-
預設情況下,不存才計算欄位。他們在請求時被計算並返回。 設置
store=True
將在資料庫中存儲計算及欄位並啟動開啟欄位搜索。 -
也可以通過設置
search
參數開啟在計算欄位上的搜索。該參數值為一個返回搜索條件的方法名稱 。upper_name = field.Char(compute='_compute_upper', search='_search_upper') def _search_upper(self, operator, value): if operator == 'like': operator = 'ilike' return [('name', operator, value)]
在對模型進行實際搜索之前處理domain時調用該搜索方法。它必須返回與條件
field operator value
等效的domain -
計算欄位預設值。為了允許對計算欄位進行設置,使用
inverse
參數。該參數值為反向計算並設置相關欄位的函數的名稱:document = fields.Char(compute='_get_document', inverse='_set_document') def _get_document(self): for record in self: with open(record.get_document_path) as f: record.document = f.read() def _set_document(self): for record in self: if not record.document: continue with open(record.get_document_path()) as f: f.write(record.document)
-
可以用同一方法同時計算多個欄位,只需對所有欄位使用同一方法並設置所有欄位
discount_value = fields.Float(compute='_apply_discount') total = fields.Float(compute='_apply_discount') @api.depends('value', 'discount') def _apply_discount(self): for record in self: # compute actual discount from discount percentage discount = record.value * record.discount record.discount_value = discount record.total = record.value - discount
警告
雖然可以對多個欄位使用相同的計算方法,但不建議對
reverse
方法使用相同的方法。在
reverse
的計算過程中,所有使用所述inverse的欄位都受到保護,這意味著即使它們的值不在緩存中,也無法計算它們。如果訪問了這些欄位中的任何一個欄位,且並且其值不在緩存中,ORM將簡單的為這些欄位返回預設值
False
。這意味著這些inverse
欄位的值(觸發inverse
方法的值除外)可能不會給出正確的值,這可能會破壞inverse
方法的預期行為
相關欄位(Related fields)
計算欄位的一種特殊情況是相關(代理)欄位,它提供當前記錄上子欄位的值。它們是通過設置related
參數來定義的,與常規計算欄位一樣,它們可以存儲:
nickname = fields.Char(related='user_id.partner_id.name', store=True)
related
欄位的值是通過遍歷一系列關係欄位並讀取所訪問模型上的欄位來給出的。要遍歷的欄位的完整序列由related
屬性指定
如果未重新定義某些欄位屬性,則會自動從源欄位中複製這些屬性:string
、help
、required
(僅當序列中的所有欄位都是必需的時)、groups
、digits
、size
、translate
、cleaning”、“selection
、comodel_name
、domain
和context
。所有無語義屬性都從源欄位複製。
預設的, related欄位:
- 不被存儲
- 不被覆制
- 只讀
- 超級用戶模式下被計算
像計算欄位那樣,添加 store=True
以存儲related
欄位。當其依賴被修改時,會自動重新計算related
欄位。
小技巧
如果不希望在任何依賴項更改時重新計算related
欄位,則可以指定精確的欄位依賴項:
nickname = fields.Char(
related='partner_id.name', store=True,
depends=['partner_id'])
# nickname僅在partner_id被修改時才會被重新計算,而不會在partner名稱被修改時重新計算
警告
不可以在related
欄位依賴項中包含 Many2many
或者 One2many
欄位
related
可以用於引用另一個模型中的 One2many
或Many2many
欄位,前提是通過當前模型的一個Many2one
關係來實現的。 One2many
和Many2many
不被支持,無法正確的彙總結果:
m2o_id = fields.Many2one()
m2m_ids = fields.Many2many()
o2m_ids = fields.One2many()
# Supported
d_ids = fields.Many2many(related="m2o_id.m2m_ids")
e_ids = fields.One2many(related="m2o_id.o2m_ids")
# Won't work: use a custom Many2many computed field instead
f_ids = fields.Many2many(related="m2m_ids.m2m_ids")
g_ids = fields.One2many(related="o2m_ids.o2m_ids")
自動生成的欄位
-
odoo.fields.id
ID欄位
如果當前記錄集長度為1,返回記錄集中唯一記錄的ID。否則拋出一個錯誤
訪問日誌欄位
如果啟用_log_access
,自動設置並更新這些欄位。當未用到這些欄位時,以禁用它以阻止創建或更新表中這些欄位。
預設的 _log_access
被設置為 _auto
的值。
-
odoo.fields.create_date
創建記錄時存儲創建時間,
Datetime
類型 -
odoo.fields.create_uid
存儲記錄創建人,
Many2one
to ares.users
-
odoo.fields.write_date
存儲記錄最後更新時間,
Datetime
類型 -
odoo.fields.write_uid
存儲記錄最後更新人,
Many2one
to ares.users
.
警告
必須對odoo.models.TransientModel
模型開啟_log_access
保留欄位名稱
除了自動欄位之外,還有一些欄位名是為預定義行為保留的。當需要相關行為時,應在模型上定義它們:
-
odoo.fields.name
_rec_name
的預設值,用於在需要代表性“命名”的上下文中顯示記錄。odoo.fields.Char
類型 -
odoo.fields.active
切換記錄的全局可見性,如果
active
設置為False
,則記錄在大多數搜索和列表中不可見。odoo.fields.Boolean
類型 -
odoo.fields.state
對象的聲明周期階段,供
fields.[Selection
的states
屬性使用 -
odoo.fields.parent_id
_parent_name
的預設值,用於以樹結構組織記錄,併在domain中啟用child_of
和parent_of
運算符。Many2one
欄位。 -
odoo.fields.parent_path
當
_parent_store
設置為True
時,用於存儲反映[_parent_name
]樹結構的值,並優化搜索domain中的child_of
和parent_of
運算符。必須使用index=True
聲明才能正確操作。odoo.fields.Char
類型 -
odoo.fields.company_id
用於Odoo多公司行為的主欄位名。供
:meth:~Odoo.models._check_company
用於檢查多公司一致性。定義記錄是否在公司之間共用(沒有值)還是僅由給定公司的用戶訪問。Many2one
:類型:res_company
記錄集(Recordset)
與模型和記錄的交互是通過記錄集執行的,記錄集是同一模型的記錄的有序集合。
警告
與名稱所暗示的相反,記錄集當前可能包含重覆項。這在未來可能會改變。
在模型上定義的方法是在記錄集上執行的,方法的self
是一個記錄集:
class AModel(models.Model):
_name = 'a.model'
def a_method(self):
# self can be anything between 0 records and all records in the
# database
self.do_operation()
對記錄集進行迭代將產生新的單條記錄的記錄集,這與對Python字元串進行迭代產生單個字元的字元串非常相似:
def do_operation(self):
print(self) # => a.model(1, 2, 3, 4, 5)
for record in self:
print(record) # => a.model(1), then a.model(2), then a.model(3), ...
欄位訪問
記錄集提供了一個“Active Record” 介面:模型欄位可直接作為記錄的屬性直接讀取和寫入。
註解
當訪問潛在多條記錄的記錄集上的非關係欄位時,使用mapped()
,該函數返回一個列表:
total_qty = sum(self.mapped('qty')) # mapped返回一個列表,形如[2,4,5]
欄位值也可以像字典項一樣訪問。設置欄位的值會觸發對資料庫的更新:
>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob
警告
- 嘗試讀取多條記錄上的欄位將引發非關係欄位的錯誤。
- 訪問一個關係欄位(
Many2one
,One2many
,Many2many
),總是返回記錄集,如果未設置欄位的話,則返回空記錄集。
記錄緩存和預取
Odoo為記錄的欄位維護一個緩存,這樣,不是每個欄位的訪問都會發出資料庫請求。
以下示例僅為第一條語句查詢資料庫:
record.name # 第一次訪問從資料庫獲取值
record.name # 第二次訪問從緩存獲取值
為了避免一次讀取一條記錄上的一個欄位,Odoo會按照一些啟髮式方法預取個記錄和欄位,以獲得良好的性能。一旦必須在給定記錄上讀取欄位,ORM實際上會在更大的記錄集上讀取該欄位,並將返回的值存儲在緩存中以供後續使用。預取的記錄集通常是通過迭代獲得記錄的記錄集。此外,所有簡單的存儲欄位(布爾值、整數、浮點值、字元、文本、日期、日期時間、選擇、many2one)都會被提取;它們對應於模型表的列,併在同一查詢中高效地獲取。
考慮以下示例,其中partners
為包含1000條記錄的記錄集。如果不進行預取,迴圈將對資料庫進行2000次查詢。使用預取,只進行一次查詢
for partner in partners:
print partner.name # first pass prefetches 'name' and 'lang'
# (and other fields) on all 'partners'
print partner.lang
預取也適用於輔助記錄:當讀取關係欄位時,它們的值(即記錄)將被訂閱以供將來預取。訪問這些輔助記錄之一將預取同一模型中的所有輔助記錄。這使得以下示例僅生成兩個查詢,一個用於合作伙伴,另一個用於國家/地區:
countries = set()
for partner in partners:
country = partner.country_id # first pass prefetches all partners
countries.add(country.name) # first pass prefetches all countries
方法修飾器
Odoo API模塊定義了Odoo環境和方法修飾符
-
odoo.api.autovacuum(method)
[源代碼]修飾一個方法,使其由日常vacuum cron作業(模型
ir.autovacuum
)調用。這通常用於垃圾收集之類的不需要特定cron作業的任務 -
odoo.api.constrains(*args)
[源代碼]裝飾一個約束檢查器
每個參數必須是校驗使用的欄位名稱:
@api.constrains('name', 'description') def _check_description(self): for record in self: if record.name == record.description: raise ValidationError("Fields name and description must be different")
當記錄的某個命名欄位被修改時調用裝飾器函數。
如果校驗失敗,應該拋出
ValidationError
警告
@constrains
僅支持簡單的欄位名稱,不支持並忽略點分名稱(關係欄位的欄位,比如partner_id.customer
)@constrains
僅當修飾方法中聲明的欄位包含在create
或write
調用中時才會觸發。這意味著視圖中不存在的欄位在創建記錄期間不會觸發調用。必須重寫create
,以確保始終觸發約束(例如,測試是否缺少值) -
odoo.api.depends(*args)
[源代碼]返回一個裝飾器,該裝飾器指定
compute
方法的欄位依賴關係(對於新型函數欄位)。參數支持是由點分隔的欄位名序列組成的字元串:pname = fields.Char(compute='_compute_pname') @api.depends('partner_id.name', 'partner_id.is_company') def _compute_pname(self): for record in self: if record.partner_id.is_company: record.pname = (record.partner_id.name or "").upper() else: record.pname = record.partner_id.name
有的也可能傳遞一個函數作為參數,這種情況下,依賴通過調用 在這種情況下,通過使用欄位的模型調用函數來提供依賴項
-
odoo.api.depends_context(*args)
[源代碼]返回一個修飾符,該修飾符指定非存儲的“compute”方法的上下文依賴項。每個參數都是上下文字典中的鍵:
price = fields.Float(compute='_compute_product_price') @api.depends_context('pricelist') def _compute_product_price(self): for product in self: if product.env.context.get('pricelist'): pricelist = self.env['product.pricelist'].browse(product.env.context['pricelist']) else: pricelist = self.env['product.pricelist'].get_default_pricelist() product.price = pricelist.get_products_price(product).get(product.id, 0.0)
所有依賴項都必須是可哈希的。以下鍵具有特殊支持:
company
(上下文中的值或當前公司id),uid
(當前用戶ID和超級用戶標記),active_test
(env.context
或者field.context
中的值).
-
odoo.api.model(method)
[源代碼]修飾一個record-style的方法,其中
self
是一個空記錄集,但其內容不相關,只有模型相關,可以理解為不會創建對應資料庫記錄的模型對象。模型層面的操作需要添加此修飾器,相當於類靜態函數@api.model def method(self, args): ...
-
odoo.api.model_create_multi(method)
[源代碼]修飾一個以字典列表為參數,並創建多條記錄的方法。可能僅通過一個字典或者字典列表調用該方法:
record = model.create(vals) records = model.create([vals, ...])
-
odoo.api.onchange(*args)
[源代碼]返回一個修飾器來修飾給定欄位的onchange方法。
在出現欄位的表單視圖中,當修改某個給定欄位時,將調用該方法。在包含表單中存在的值的偽記錄上調用該方法。該記錄上的欄位賦值將自動返回客戶端。
每個參數必須是欄位名:
@api.onchange('partner_id') def _onchange_partner(self): self.message = "Dear %s" % (self.partner_id.name or "") return { 'warning': {'title': "Warning", 'message': "What is this?", 'type': 'notification'}, }
如果類型設置為通知(
notification
),則警告將顯示在通知中。否則,它將作為預設值顯示在對話框中警告
@onchange
僅支持簡單的欄位名稱,不支持並自動忽略點分名稱(關係欄位的欄位,比如partner_id.tz
)危險
由於
@onchange
返回偽記錄的記錄集,對上述記錄集調用任何一個CRUD方法(create()
,read()
,write()
,unlink()
)都是未定義的行為,因為它們可能還不存在於資料庫中。相反,只需像上面的示例中所示那樣設置記錄的欄位或調用update()
方法警告
one2many
或者many2many
欄位不可能通過onchange
修改其自身。這是客戶端限制 - 查看 #2693 -
odoo.api.returns(model, downgrade=None, upgrade=None)
[源代碼]為返回
model
實例的方法返回一個修飾器-
參數
model – 模型名稱,或者表示當前模型的
'self'
downgrade – 一個用於轉換record-style的
value
為傳統風格輸出的函數downgrade(self, value, *args, **kwargs)
upgrade – 一個用於轉換傳統風格(traditional-style)的
value
為record-style的輸出的函數upgrade(self, value, *args, **kwargs)
參數
self
,*args
和**kwargs
以record-style方式傳遞給方法修飾器將方法輸出適配api風格:
id
,ids
或者False
對應傳統風格,而記錄集對應記錄風格:@model @returns('res.partner') def find_partner(self, arg): ... # return some record # output depends on call style: traditional vs record style partner_id = model.find_partner(cr, uid, arg, context=context) # recs = model.browse(cr, uid, ids, context) partner_record = recs.find_partner(arg)
註意,被修飾的方法必須滿足那約定。
這些修飾器是自動繼承的:重寫被修飾的現有方法的方法將被相同的
@return(model)修飾
-
環境(Environment)
Environment
存儲ORM使用的各種上下文數據:資料庫游標(用於資料庫查詢)、當前用戶(用於訪問許可權檢查)和當前上下文(