1. 程式人生 > >Odoo12 ORM API ☞ Method decorators

Odoo12 ORM API ☞ Method decorators

Method decorators(裝飾器)

該模組提供的元素用於管理兩種不同API樣式,即“traditional”(“傳統”)和 “record”(“記錄”)風格。
在“traditional” 風格中,諸如資料庫遊標、使用者id、context字典和記錄集ids(通常表示為cr,uid,context,id)引數都是顯式的傳遞給各方法。在“record”樣式中,這些引數被封裝在模型例項中,這使其具有更加面向物件的感覺。
例如,宣告:

model = self.pool.get(MODEL)
ids = model.search(cr, uid, DOMAIN, context=context)
for rec in model.browse(cr, uid, ids, context=context):
    print rec.name
model.write(cr, uid, ids, VALUES, context=context)

也可以寫成:

env = Environment(cr, uid, context) # cr, uid, context wrapped in env
model = env[MODEL]                  # retrieve an instance of MODEL
recs = model.search(DOMAIN)         # search returns a recordset
for rec in recs:                    # iterate over the records
    print rec.name
recs.write(VALUES)                  # update all records in recs

用傳統方式寫的方法會啟發性的自動根據一些基於引數名稱進行裝飾。


odoo.api.multi(method)

裝飾一個"record-style"方法,其中self是記錄集, 該方法通常定義對記錄的操作。例如:

@api.multi
def method(self, args):
    ...

在記錄樣式和傳統樣式中呼叫,例如:

# recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, ids, args, context=context)

odoo.api.model(method)

裝飾一個"record-style"方法,但它的內容不相關,只有模型。例如:

@api.model
def method(self, args):
    ...

在記錄樣式和傳統樣式中呼叫,例如:

# recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, args, context=context)

請注意,沒有 ids 以傳統方式傳遞給方法。


odoo.api.depends(*args)

返回一個裝飾器,它指定欄位所依賴的“compute”方法(對於新樣式中功能欄位)。
每個引數必須是一個字串,該字串由以點分隔的欄位名稱序列組成:

pname = fields.Char(compute='_compute_pname')

@api.one
@api.depends('partner_id.name', 'partner_id.is_company')
def _compute_pname(self):
    if self.partner_id.is_company:
        self.pname = (self.partner_id.name or "").upper()
    else:
        self.pname = self.partner_id.name

也可以將單個函式作為引數傳遞。在這種情況下,通過使用欄位的模型呼叫函式來給出依賴關係。


odoo.api.constrains(*args)

裝飾約束檢查器。每個引數必須是檢查中使用的欄位名稱:

@api.one
@api.constrains('name', 'description')
def _check_description(self):
    if self.name == self.description:
        raise ValidationError("Fields name and description must be different")

當命名欄位做出修改之後呼叫。
如果驗證失敗,則會觸發***ValidationError***。

Warning
@constrains 只支援簡單的欄位名稱,通過點出來的欄位(關係欄位的欄位,例如partner_id.customer)不被支援且被忽略。
@constrains 只有當在create或write呼叫中包含裝飾方法中的宣告欄位時才會觸發。這意味著檢視中不存在的欄位在建立記錄期間不會觸發呼叫。重寫create時必須確保始終觸發約束(例如,測試缺少值)。


odoo.api.onchange(*args)

返回裝飾器以裝飾給定欄位的onchange方法。每個引數必須是欄位名稱:

@api.onchange('partner_id')
def _onchange_partner(self):
    self.message = "Dear %s" % (self.partner_id.name or "")

在欄位顯示的form檢視中,當修改其中一個給定欄位時,將呼叫該方法。在包含form中存在的值的 偽記錄 上呼叫該方法。該記錄上的欄位更改值會自動傳送回客戶端。
該方法也可以返回字典以更改domains並彈出警告訊息,就像在舊API中一樣:

return {
    'domain': {'other_id': [('partner_id', '=', partner_id)]},
    'warning': {'title': "Warning", 'message': "What is this?"},
}

Warning
只支援簡單欄位,通過點出來的欄位(關係欄位的欄位,例如partner_id.tz)不被支援且被忽略。


odoo.api.returns(model, downgrade=None, upgrade=None)

返回返回模型例項的方法的裝飾器。

Parameters:
  model – 模型名稱,或者當前模型對應的 self
  downgrade – 方法 downgrade(self, value, *args, **kwargs) 將記錄樣式值轉換為傳統樣式的輸出
  upgrade – 方法 upgrade(self, value, *args, **kwargs) 將傳統風格的值轉換為記錄式輸出

引數self,* args和 **kwargs是以記錄樣式傳遞給方法的引數。

對於傳統風格和記錄樣式的記錄集,裝飾器將方法輸出調整為api樣式: id, ids or 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)

請注意,修飾方法必須滿足約定。
裝飾器會自動繼承:重寫裝飾的現有方法的方法必須使用相同的方法 @returns(model) 進行修飾。


odoo.api.one(method)

裝飾一個記錄樣式的方法,其中self應該是一個單例例項。裝飾方法自動迴圈記錄並列出結果列表。如果方法用returns()修飾,它會連線生成的例項。例如:

@api.one
def method(self, args):
    return self.name

可以在記錄和傳統樣式中呼叫,例如:

# recs = model.browse(cr, uid, ids, context)
names = recs.method(args)

names = model.method(cr, uid, ids, args, context=context)

從版本9.0開始不推薦使用:one() 經常使程式碼不那麼清晰,並且時不時以開發人員和讀者想不到的地方出現問題。
強烈建議使用 multi() ,要麼迭代自記錄集,要麼確保記錄集是帶有ensure_one()的單個記錄。


odoo.api.v7(method_v7)

裝飾一個只支援舊式api的方法,可以通過重新定義具有相同名稱並用v8()修飾的方法來提供新式api:

@api.v7
def foo(self, cr, uid, ids, context=None):
    ...

@api.v8
def foo(self):
    ...

如果一種方法呼叫另一種方法,則必須特別小心.因為該方法可能被重寫。應該從當前的類中呼叫該方法(say MyClass),例如:

@api.v7
def foo(self, cr, uid, ids, context=None):
    # Beware: records.foo() may call an overriding of foo()
    records = self.browse(cr, uid, ids, context)
    return MyClass.foo(records)

請注意,裝飾器方法使用第一種方法的文件字串。


odoo.api.v8(method_v8)

Decorate a method that supports the new-style api only。可以通過重新定義具有相同名稱的方法並使用v7()修飾來提供舊式api:

@api.v8
def foo(self):
    ...

@api.v7
def foo(self, cr, uid, ids, context=None):
    ...

請注意,裝飾器方法使用第一種方法的文件字串。