1. 程式人生 > >Odoo12 ORM API ☞ Recordsets

Odoo12 ORM API ☞ Recordsets

Recordsets(記錄集)


8.0版中的新功能: 此頁面記錄了Odoo 8.0中新增的 NEW API,它應該是未來的主要開發API。Odoo12依舊提供相容OpenERP 7.0更甚之前中"old API",但此處不再提及"old API",如需請參閱之前API文件。

與模型和記錄的互動是通過Recordsets執行的,Recordsets是同一模型的有序記錄集。

Warning!
Recordsets,名稱中為set,即為無重複記錄集,但目前Recordsets(記錄集)可能包含重複項。後邊可能會有所改變。

模型中定義的方法在記錄集上執行,方法的 self

是記錄集:

class AModel(models.Model):
    _name = 'a.model'
    def a_method(self):
        # self can be anywhere between 0 records and all records in the
        # database
        self.do_operation()

迭代記錄集將得到新的單個記錄(“singletons”),就像迭代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), ...

Field access(欄位訪問)

Recordsets提供“Active Record” 介面:模型欄位可以作為屬性直接從記錄中讀取和寫入,但僅限於單例(single-record recordsets)。欄位的值就可以像字典一樣直接訪問,這種方式要比使用欄位的*“getattr()”*方法來訪問要優雅和安全。當設定欄位的值時會觸發資料庫的更新操作。

>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob

當試圖對多記錄(multiple records)的進行讀取或者寫入操作時會報錯!
訪問一個關係欄位(如Many2one,One2many,Many2many)會始終返回記錄集,如果未設定欄位,則為空。

Danger!
對欄位的每個賦值都會觸發資料庫更新,在同時設定多個欄位或在多個記錄上設定欄位(相同的值)時,請使用write():

# 3 * len(records) database updates
for record in records:
    record.a = 1
    record.b = 2
    record.c = 3

# len(records) database updates
for record in records:
    record.write({'a': 1, 'b': 2, 'c': 3})

# 1 database update
records.write({'a': 1, 'b': 2, 'c': 3})

Record cache and prefetching(記錄快取和預取)

Odoo會為記錄欄位維護一個快取,這樣就不需要訪問每個欄位都發出資料庫請求,如果每取一個欄位就去資料庫查詢一次,效能就會變的很糟糕。示例中僅針對第一個語句查詢資料庫,第二次會從快取中取值:

record.name             # first access reads value from database
record.name             # second access gets value from cache

為了避免一次讀取一條記錄上一個欄位,Odoo按照一些啟發式方法預取記錄和欄位以獲得良好的效能。一旦必須在給定記錄上讀取欄位,ORM實際上會在在更大的記錄集上讀取該欄位,並將返回的值儲存在快取中供以後使用。預取記錄集通常是來自迭代形成的記錄集。此外,所有簡單的儲存欄位(boolean, integer, float, char, text, date, datetime, selection, 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

Set operations(集合操作)

Recordsets 是不可變的,但可以使用各種set操作組合相同模型的集合,返回新的Recordsets 。設定操作保留順序。

  • record in set 返回 record 是否存在於 set 中。record not in set 即判斷是否不在 set 中。
  • set1 <= set2set1 < set2 返回 set1 是否是 set2 的一個子集(或嚴格是一個子集)。
  • set1 >= set2set1 > set2 返回 set1 是否是 set2 的一個父(超)集(或嚴格是一個父集)。
  • set1 | set2 返回兩個recordsets的並集,包含任一 set 中都存在的所有記錄的新記錄集。
  • set1 & set2 返回兩個recordsets的交集,包含兩個 set 中都存在的所有記錄的新記錄集。
  • set1 - set2 返回僅包含 set1 的記錄的新記錄集,這些記錄不存在於 set2 中。

Other recordset operations(其他集合操作)

Recordsets 是可迭代的,因此通常的Python工具可用於轉換(map(),sorted(),itertools.ifilter,…)但是這些工具返回 listiterator, 去掉了在返回結果上呼叫方法或使用集合操作的能力。
因此,Recordsets 提供這些操作返回recordsets (記錄集)本身的操作方法(如果可能):

filtered()
返回僅包含滿足提供的條件函式的記錄的記錄集。條件也可以是一個字串按欄位為true或false進行過濾:

# only keep records whose company is the current user's
records.filtered(lambda r: r.company_id == user.company_id)

# only keep records whose partner is a company
records.filtered("partner_id.is_company")

sorted()
返回按提供的key函式排序的記錄集。如果未提供key,將使用模型的預設排序順序:

# sort records by name
records.sorted(key=lambda r: r.name)

mapped()
將提供的函式應用於Recordset中的每個record(記錄),如果結果是Recordset,則返回Recordset:

# returns a list of summing two fields for each record in the set
records.mapped(lambda r: r.field1 + r.field2)

提供的函式可以是獲取欄位值的字串:

# returns a list of names
records.mapped('name')

# returns a recordset of partners
record.mapped('partner_id')

# returns the union of all partner banks, with duplicates removed
record.mapped('partner_id.bank_ids')