## 記錄集
[TOC]
model的數據是通過數據集合的形式來使用的,定義在model里的函數執行時它們的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()
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), ...
~~~
獲取有關聯關系的字段(one2many,many2one,many2many)也是返回一個數據集合,如果字段為空則返回空的集合。
> 每個賦值語句都會觸發數據庫字段更新,同時更新多個字段時可使用或者更新多條記錄時使用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})
~~~
* 數據緩存和預讀取
odoo會為記錄保留一份緩存,它有一種內置的預讀取機制,通過緩存來提升性能。
* 集合運算符
* record in set返回record是否在set中,record須為單條記錄,record not in set反之
* set1 <= set2 返回set1是否為set2的子集
* set1 >= set2 返回set2是否為set1的子集
* set1 | set2 返回set1和set2的并集
* set1 & set2 返回set1和set2的交集
* set1 - set2 返回在集合set1中但不在set2中的記錄
* 其他集合運算
* filtered() 返回滿足條件的數據集,如
~~~
# 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() 返回根據提供的鍵排序之后的結果
~~~
# sort records by name
records.sorted(key=lambda r: r.name)
~~~
* mapped() 返回應用了指定函數之后的結果集
~~~
#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')
~~~
## 運行環境
運行環境保存了很多ORM相關的變量:數據庫查詢游標、當前用戶、元數據,還存有緩存。所有的model數據集都有不可改變的環境變量,可使用`env`來訪問,如records.env.user,records.env.cr,records.env.context,運行環境還可用于為其他模型初始化一個空的集合并對該模型進行查詢
~~~
self.env['res.partner'].search([['is_company', '=', True], ['customer', '=', True]])
#res.partner(7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74)
~~~
* 更改運行環境
可以基于一個運行環境量自定義,以得到擁有新運行環境的數據集
* sudo() 使用現有數據集創建一個新運行環境,得到一個基于新運行環境的數據集的拷貝
~~~
# create partner object as administrator
env['res.partner'].sudo().create({'name': "A Partner"})
# list partners visible by the "public" user
public = env.ref('base.public_user')
env['res.partner'].sudo(public).search([])
~~~
* with_context()
一個參數時可用于替換當前運行環境的context,多個參數時通過keyword添加到當前運行環境context或單參數時設置的context
* with_env() 完整替換當前運行環境
## 常用ORM函數
* search() 接收domain表達式參數,返回符合條件的數據集合,可以通過limit,offset參數返回一個子集,還可通過order參數對數據排序
~~~
>>> self.search([('is_company', '=', True), ('customer', '=', True)])
res.partner(7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74)
>>> self.search([('is_company', '=', True)], limit=1).name
'Agrolait'
~~~
> 如果只需要知道滿足條件的數據數量,可以使用search_count()函數
* create() 接收多個字段、值的組合,返回新創建的數據集
~~~
>>> self.create({'name': "New Name"})
res.partner(78)
~~~
* write() 接收多個字段、值組合,會對指定數據集的所有記錄進行修改,不返回
~~~
self.write({'name': "Newer Name"})
~~~
* browse() 根據數據的id或者一組id來查找,返回符合條件的數據集合
~~~
>>> self.browse([7, 18, 12])
res.partner(7, 18, 12)
~~~
* exists() 得到某個數據集中保留在數據庫中的那部分,或在對一個數據集進行處理后重新賦值
~~~
if not record.exists():
raise Exception("The record has been deleted")
records.may_remove_some()
# only keep records which were not deleted
records = records.exists()
~~~
* ref() 運行環境函數根據提供的external id返回對應的數據記錄
~~~
>>> env.ref('base.group_public')
res.groups(2)
~~~
* ensure_one() 檢驗某數據集是否只包含單條數據,如果不是則報錯
~~~
records.ensure_one()
# 和下面的語句效果相同
assert len(records) == 1, "Expected singleton"
~~~
## 創建模型
模型字段就是定義的模型的屬性,默認情況下字段名稱就是屬性名的大寫,也可通過string參數指定
~~~
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
field2 = fields.Integer(string="an other field")
~~~
可以通過default參數設置字段的默認值,默認值可以是特定的值,也可以指向一個函數
~~~
a_field = fields.Char(default="a value")
def compute_default_value(self):
return self.get_value()
a_field = fields.Char(default=compute_default_value)
~~~
* 實時計算的字段
字段也可以是通過實時計算得來的,指定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
~~~
1.依賴的字段如果是子集里的字段,可用.表示
~~~
@api.depends('line_ids.value')
def _compute_total(self):
for record in self:
record.total = sum(line.value for line in record.line_ids)
~~~
2.默認情況下實時計算的字段是不保存到數據庫的,可以通過store=True參數來設置保存且可以搜索
3.可以為實時計算字段設置search參數來使其可搜索,參數的值須是一個返回domain表達式的函數
~~~
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)]
~~~
4.實時計算的字段也可以通過inverse參數來賦值,通過一個反轉compute的函數來設置相關的字段值
~~~
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)
~~~
5.多個字段可以同時使用同一個方法計算而來
~~~
discount_value = fields.Float(compute='_apply_discount')
total = fields.Float(compute='_apply_discount')
@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
~~~
6.關聯字段
關聯字段是實時計算字段的一個特例,它會給出子集對應的值,通過related參數來定義,就像普通字段一樣可以保存到數據庫
`nickname = fields.Char(related='user_id.partner_id.name', store=True)`
* onchange:實時更新用戶界面
當用戶在表單中更改某個字段的值時,其他相關字段可以在不需保存的情況下實時更新
~~~
@api.onchange('field1', 'field2') # 當這兩個字段值改變時調用該函數
def check_change(self):
if self.field1 < self.field2:
self.field3 = True
~~~
實時計算字段和onchange方法會自動在客戶端調用,不需要在視圖里做特別聲明,但可以在視圖中通過on_change="0"參數來阻止onchange函數的自動調用
`<field name="name" on_change="0"/>`
* 低級SQL
運行環境的cr屬性指向當前數據庫查詢的游標,在需要進行ORM沒有提供的復雜查詢或性能優化時,可以通過它直接執行查詢
`self.env.cr.execute("some_sql", param1, param2, param3)`
但由于運行環境變量里同時存有大量緩存,所以在進行create/update,delete操作后需要使用invalidate_all()方法清除緩存: `self.env.invalidate_all()`,select方法是不需要更新緩存的,因為沒有對數據進行更改
## 模型使用
odoo的模型都是從class odoo.models.Model(pool, cr)繼承而來
模型的屬性結構:
1._name 業務對象的名稱
2._rec_name 可選的name字段名稱,供osv的name_get()方法使用,默認值name
3._inherit 如果設置了**name屬性,它的取值是單個或多個父級的模型名稱;沒有設置**name屬性時,只能是單個模型名稱
4._order 在搜索的時候的默認排序,默認值是id
5._auto 指定該表是否需要創建,默認值是True,如果設置成False需要重寫init方法來創建表
6._table 當_auto設置成false時,該值為創建的表名;默認情況下會自動生成一個
7._inherits 定義上級模型關聯使用的外鍵
~~~
_inherits = {
'a.model': 'a_field_id',
'b.model': 'b_field_id'
}
~~~
8._sql_constraints 通過一個(name, sql_definition, message)的三元組列表定義表的sql級別約束
9._parent_store 與 parent_left , parent_right 一起使用,可得到一個嵌套的集合,默認是不啟用的
### CRUD
* create(vals)
使用傳遞的vals參數為模型生成一條新記錄,參數示例:`{'field_name': field_value, ...}`,該方法返回該新創建的記錄
* browse([ids])
返回滿足條件的記錄集合,參數可以為空或單個id或一系列id
* unlink() 刪除當前集合的數據
* write(vals) 使用提供的數據更新當前集合里的所有記錄,參數示例:`{'foo': 1, 'bar': "Qux"}`
* int或float型字段,給定的值須為對應的整型或浮點型
* 布爾型字段,對應的值須為bool型
* Selection字段,給定的值須符合條件
* Many2one字段,給定的值須與對應的數據庫記錄相符
* 其他無關聯關系的字段使用字符串作值
* One2many和Many2many字段通過一個特殊的格式命令來操縱對應字段值,通過一系列三元組按順序來對數據進行操作,下面是一些常用的:
~~~
(0, _, values) 為指定的value字典添加一條新記錄
(1, id, values) 更新一條現有記錄,條件是id為指定id且value在指定values中,不能在create方法里使用
(2, id, _) 將指定id的數據從數據集中刪除并從數據庫刪除,不能在create里使用
(3, id, _) 將指定id的數據從數據集中刪除但不從數據庫刪除,不能用在One2many關系及create里
(4, id, _) 將指定id的數據添加到數據集中,不能用在One2many關系上
(5, _, _) 將集合的所有數據刪除,相當于當3作用于每條記錄上
(6, _, ids) 使用ids列表里匹配的所有數據替換當前記錄,相當于先執行5再循環執行4
~~~
* read([fields]) 從self里讀取指定的字段,專供rpc使用
* read_group(domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True) 得到一個通過groupby參數分組后的記錄的列表
~~~
domain 搜索條件的domain表達式列表 [['field_name', 'operator', 'value'], ...]
fields (list) 需要展示出來的字段列表
groupby (list) 用來分組的表達式列表,分組表達式可以是單個字段或者一個函數如:'field:groupby_function',目前函數只支持 'day', 'week', 'month', 'quarter' or 'year'并且只能作用在date和datetime字段上
offset (int) 可選參數,代表從哪個條記錄開始取
limit (int) 可選參數,代表取出多少條記錄
orderby (list) 可選參數,和search函數的orderby參數一樣
lazy (bool) 值為true時,記錄只會根據第一個groupby值進行分組,后面的groupby參數會被存在__context 中;值為false時會把所有分組條件一起執行
~~~
### Searching
* search(args[, offset=0][, limit=None][, order=None][, count=False])
根據args參數里的domain表達式來搜索所有記錄,參數列表:
1.args domain表達式,為空時返回所有記錄
2.offset (int) 從第幾條記錄開始取
3.limit (int) 返回記錄行數的最大值
4.order (str) 排序的字段
5.count (bool) 當值為True的時候只返回匹配記錄的條數
* search_count(args)
返回根據給定domain表達式參數查詢所得到的記錄條數
* name_search(name='', args=None, operator='ilike', limit=100)
返回根據name條件來查詢,并滿足args指定的domain表達式的記錄集合
~~~
name (str) -- 用來匹配的name字符串
args (list) -- domain表達式列表
operator (str) -- 用來匹配的操作符,如: 'like' , '='.
limit (int) -- 可選參數,最多返回的記錄行數
~~~
### 記錄集合操作
* ids 得到當前記錄集合的id列表
* ensure_one() 驗證一個記錄集合是否只包含一條記錄
* exists() 返回當前記錄集中真正存在的子集,并把緩存中未刪除的部分做標記,可用于判斷`if record.exists():`
* filtered(func) 返回滿足func參數內條件的記錄集合,參數可以是一個函數或者用.分隔的字段列表
* sorted(key=None, reverse=False) 返回按key排序之后的記錄集,key參數可以是一個返回單個key的函數或字段名稱或為空,reverse參數為True時即為倒序
* mapped(func) 將func函數應用到所有記錄上,并返回記錄列表或集合
### 環境切換
* sudo([user=SUPERUSER]) 返回通過指定用戶得到的新記錄集,默認會返回SUPERUSER的記錄集(前提是權限沒有問題)
* with_context([context][, **overrides])
返回當前記錄集在擴展環境下的新記錄集,擴展環境可以由指定環境和overrides參數合并而成、或由當前環境和overrides參數合并而成
~~~
# current context is {'key1': True}
r2 = records.with_context({}, key2=True)
# -> r2._context is {'key2': True}
r2 = records.with_context(key2=True)
# -> r2._context is {'key1': True, 'key2': True}
~~~
* with_env(env) 返回在指定環境下的新版記錄集合
### 字段和視圖查詢
* fields_get([fields][, attributes])
以數據字典的形式返回字段的定義,通過繼承得來的字段也會在其中,string/help/selection屬性會自動被翻譯
* fields參數是字段列表、為空或不傳返回所有字段
* attributes 可指定字段的屬性、為空或不傳時返回全部的
* fields_view_get([view_id | view_type='form'])
返回指定視圖的具體組成如:字段,模型,視圖結構
> 參數列表:
> view_id 視圖的id或None
> view_type 當view_id參數為空時指定視圖類型如form,tree等
> toolbar 參數為true時將上下文動作包含在內
### 其他方法
* default_get(fields) 獲取指定字段的默認值
* name_get() 以列表形式返回每條記錄的描述,默認是display_name字段
* name_create(name) 相當于調用create方法創建一條新記錄而只設置一個display_name
### 內置字段
* id 數據識別字段
* _log_access 決定記log的字段(created_date,write_uid..)是否創建,默認值True
* create_date 記錄創建的時間
* create_uid 創建人的id,關聯到res.users
* write_date 記錄最近的修改時間
* write_uid 最近修改記錄的用戶id,關聯到res.users
### 保留字段
一些字段名稱是給model保留的,用來實現一些預定義的功能。當需要實現對應功能是需要對相應的保留字段進行定義
* name(Char) -- _rec_name的默認值,在需要用來展示的時候使用
* active(Boolean) -- 設置記錄的全局可見性,當值為False時通過search和list是獲取不到的
* sequence(Integer) -- 可修改的排序,可以在列表視圖里通過拖拽進行排序
* state(Selection) -- 對象的生命周期階段,通過fileds的states屬性使用
* parent_id(Many2one) -- 用來對樹形結構的記錄排序,并激活domain表達式的child_of運算符
* parent_left,parent_right -- 與 _parent_store結合使用,提供更好的樹形結構數據讀取
## 裝飾器函數
模塊提供了兩種api形式,在傳統形式中,所有參數明確地傳給方法;還有一種記錄行形式,提供了更加面向對象化的操作方式
~~~
#傳統方式:
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)
在記錄行方式下裝飾一個對記錄進行操作的方法
~~~
@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)
在記錄行方式下裝飾一個內容不明確、但模型明確的方法
~~~
@api.model
def method(self, args):
...
#傳統方式
# recs = model.browse(cr, uid, ids, context)
recs.method(args)
model.method(cr, uid, args, context=context)
~~~
* odoo.api.depends(*args)
返回為compute方法指定依賴字段的裝飾器,每個參數必須是字符串
~~~
name = 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錯誤,且不支持關聯字段檢驗
* odoo.api.onchange(*args)
返回一個監控指定字段的onchange方法的裝飾器,每個參數必須是字段名稱
~~~
@api.onchange('partner_id')
def _onchange_partner(self):
self.message = "Dear %s" % (self.partner_id.name or "")
~~~
> 該函數可能會返回 以數據字典形式組裝的當前更改字段的domain表達式和一個警告消息,不支持關聯字段處理
>
> ~~~
> return {
> 'domain': {'other_id': [('partner_id', '=', partner_id)]},
> 'warning': {'title': "Warning", 'message': "What is this?"},
> }
> ~~~
* odoo.api.returns(model, downgrade=None, upgrade=None)
返回一個獲取model實例的方法的裝飾器
> 參數列表
> model 模型名稱,self代表當前模型
> downgrade 一個將value值從記錄形式轉化為傳統形式的方法:downgrade(self, value, *args, **kwargs)
> upgrade 一個將value從傳統形式轉化為記錄形式的方法:upgrade(self, value, *args, **kwargs)
self,*args,**kwargs是在傳統形式下需要傳的參數
`該裝飾器將函數的輸出變成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)
~~~
* odoo.api.one(method)
裝飾一個需要將self作為單例模式使用的記錄形式方法,該方法自動對記錄進行循環并將結果組織成列表,當記錄行被returns方法裝飾過時,該方法會將對應的實例組織起來,從9.0版本開始不用了
* odoo.api.v7(method_v7) 用于裝飾支持老版api的方法
* odoo.api.v8(method_v8) 用于裝飾支持新版api的方法
~~~
@api.v8
def foo(self):
...
@api.v7
def foo(self, cr, uid, ids, context=None):
...
~~~
## 字段
### 基本字段
* class odoo.fields.Field(string=, **kwargs)
> 參數列表:
> string(string) -- 用戶能看到的字段的標簽
> help(string) -- 用戶能看到的關于該字段的提示
> readonly(boolean) -- 字段是否設置為只讀,默認為False
> required(boolean) -- 字段是否為必須,默認False
> index(boolean) -- 字段是否作為索引保存在數據庫中,默認False
> default -- 字段的默認值,可以是一個特定的值或者一個有返回值的函數,可使用default=None來忽略字段的default設置
> states -- 用數據字典封裝視圖里的屬性-值對,如'readonly', 'required', 'invisible'
> groups -- 用逗號分隔的xml id列表,可以限制用戶對字段的訪問
> copy(boolean) -- 指定當數據行被復制時該字段是否被復制,默認是True,實時計算字段和one2many字段默認為False
> oldname(string) -- 之前的字段名稱,在做數據遷移的時候orm可以自動進行重命名
* 實時計算字段
可定義一個字段,它的值通過指定函數實時計算得來,定義實時計算字段只需要指定compute屬性即可,它有以下幾種參數:
> compute -- 用于計算的函數名稱
> inverse -- 逆向計算函數的函數名,可選
> search -- 實現該字段search方法的函數名
> store -- 是否在數據庫存儲該字段值,默認False
> compute_sudo -- 是否需要使用超級管理員對該字段進行重新計算
例:
~~~
upper = fields.Char(compute='_compute_upper',
inverse='_inverse_upper',
search='_search_upper')
@api.depends('name')
def _compute_upper(self):
for rec in self:
rec.upper = rec.name.upper() if rec.name else False
def _inverse_upper(self):
for rec in self:
rec.name = rec.upper.lower() if rec.upper else False
def _search_upper(self, operator, value):
if operator == 'like':
operator = 'ilike'
return [('name', operator, value)]
~~~
實時計算的方法必須用 odoo.api.depends()方法裝飾以決定其依賴于哪些字段,且同一個計算方法可用于多個計算字段,只需要在方法里將對應的字段賦值就行,search方法的返回值須是一個與條件對應的domain表達式,在對模型執行搜索處理domain表達式時調用
* 關聯字段
關聯字段的值是通過一系列的外鍵字段并通過其關聯的模型讀取,參數:`related`
屬性(string, help, readonly, required,groups, digits, size, translate, sanitize, selection, comodel_name, domain, context)只要沒有被重定義會自動從源字段復制過來,默認情況下關聯字段是不保存到數據庫的,就像實時計算字段一樣,可以通過指定store=True來指定保存
* 依賴于Company的字段
假如一個用戶屬于多個公司,那么他在不同記錄條件下得到的該字段值是不同的,參數`company_dependent -- boolean(默認False)`
* sparse 字段
sparse字段一般是不為null的,大部分這類字段用于序列化存儲,參數`sparse -- 該字段值的存儲位置`
* 增加的定義
子類可以重定義與父類同名同類型的字段,字段屬性也會從父類繼承過來并且可以被重定義
> 例:第二個子類只為state字段添加提示
~~~
class First(models.Model):
_name = 'foo'
state = fields.Selection([...], required=True)
class Second(models.Model):
_inherit = 'foo'
state = fields.Selection(help="Blah blah blah")
~~~
### 常用字段
* class odoo.fields.Char(string=, **kwargs) 字符串字段,可指定長度,一般在客戶端以單行顯示
> 參數
> size (int) -- 值的最大長度
> translate -- 啟用字段的翻譯
* class odoo.fields.Boolean(string=, **kwargs) 布爾類型
* class odoo.fields.Integer(string=, **kwargs) 整型
* class odoo.fields.Float(string=, digits=, **kwargs) 浮點型,可接受digits 參數`(total, decimal)`指定位數
* class odoo.fields.Text(string=, **kwargs) Text類型,用于儲存較多的內容
* class odoo.fields.Selection(selection=, string=, **kwargs)
> 參數
> selection -- 指定該字段的取值列表,為(value,string)列表或一個模型的方法或方法名
> selection_add -- 當該字段來自重定義時,它提供selection參數的擴展,為(value,string)列表
* class odoo.fields.Html(string=, **kwargs) 儲存html內容
* class odoo.fields.Date(string=, **kwargs) date類型
> 1.static context_today(record, timestamp=None)
> 返回客戶端時區的當前日期,可以接收一個datetime格式的參數
> 2.static from_string(value) 將ORM的值轉換為date的值
> 3.static to_string(value) 將date格式的值轉換為ORM的值
> 4.static today(*args) 以ORM值的格式返回當前日期
* class odoo.fields.Datetime(string=, **kwargs)
> 1.static context_timestamp(record, timestamp) 一般用fields.datetime.now()替代
> 2.static from_string(value) 將ORM格式的值轉換為datetime格式
> 3.static now(*args) 獲取ORM格式的當前時間
> 4.static to_string(value) 將datetime格式的值轉換為ORM接受的格式
### 關系模型字段
* class odoo.fields.Many2one(comodel_name=, string=, **kwargs)
該字段的獲取到的集合的記錄數量只會是0(無記錄)或1(單條記錄)
> 參數列表:
> comodel_name(string) -- 目標模型名稱,除非是關聯字段否則該參數必選
> domain -- 可選,用于在客戶端篩選數據的domain表達式
> context -- 可選,用于在客戶端處理時使用
> ondelete -- 當所引用的數據被刪除時采取的操作,取值:'set null', 'restrict', 'cascade'
> auto_join -- 在搜索該字段時是否自動生成JOIN條件,默認False
> delegate -- 設置為True時可以通過當前model訪問目標model的字段,與_inherits功能相同
* class odoo.fields.One2many(comodel_name=, inverse_name=, string=, **kwargs)
該字段的值是目標model的所有記錄
> 參數列表:
> comodel_name -- 目標模型名稱,
> inverse_name -- 在comodel_name 中對應的Many2one字段
> domain -- 可選,用于在客戶端篩選數據的domain表達式
> context -- 可選,用于在客戶端處理時使用
> auto_join -- 在搜索該字段時是否自動生成JOIN條件,默認False
> limit(integer) -- 可選,在讀取時限制數量
注:除非是關聯字段,否則comodel_name和inverse_name是必選參數
* class odoo.fields.Many2many(comodel_name=, relation=, column1=, column2=, string=, **kwargs)
該字段的值為一個數據集合
> 參數:
> comodel_name -- 目標模型名稱,除非是關聯字段否則該參數必選
> relation -- 可選,關聯的model在數據庫存儲的表名,默認采用comodel_name獲取數據
> column1 -- 可選,與relation表記錄相關聯的列名
> column2 -- 可選,與relation表記錄相關聯的列名
> domain -- 可選,用于在客戶端篩選數據的domain表達式
> context -- 可選,用于在客戶端處理時使用
> limit(integer) -- 可選,在讀取時限制數量
* class odoo.fields.Reference(selection=, string=, **kwargs)
基于odoo.fields.Selection
## 繼承和擴展
odoo有三種模塊化的模型繼承機制:
* 根據原有模型創建一個全新的模型,并基于新創建的模型修改,新模型與已存在的視圖兼容,并保存在同一張表中
* 從其他模塊中擴展模型,并進行替換,一般用于復制,已存在的視圖會忽略新建的模型,數據保存在新的數據表中
* 通過代理訪問其他模型的字段,可以同時繼承多個模型,數據保存在新的數據表中,新的模型會包含一個嵌入的原模型,并且該模型數據是同步的
### 傳統繼承
當_inherit和_name屬性一起使用時,odoo基于原有模型創建一個新模型,新的模型會自動繼承原模型的字段、方法等
~~~
class Inheritance0(models.Model):
_name = 'inheritance.0'
name = fields.Char()
def call(self):
return self.check("model 0")
def check(self, s):
return "This is {} record {}".format(s, self.name)
class Inheritance1(models.Model):
_name = 'inheritance.1'
_inherit = 'inheritance.0'
def call(self):
return self.check("model 1")
~~~
### 擴展
當只使用_inherit屬性時,新的模型會替代已存在的模型,當需要給模型添加字段、方法、重置屬性時比較有用
~~~
class Extension0(models.Model):
_name = 'extension.0'
name = fields.Char(default="A")
class Extension1(models.Model):
_inherit = 'extension.0'
description = fields.Char(default="Extended")
~~~
### 代理
代理模式使用_inherits屬性來指定一個模型當找不到指定字段時直接去對應的子模型查找
~~~
class Child0(models.Model):
_name = 'delegation.child0'
field_0 = fields.Integer()
class Child1(models.Model):
_name = 'delegation.child1'
field_1 = fields.Integer()
class Delegating(models.Model):
_name = 'delegation.parent'
_inherits = {
'delegation.child0': 'child0_id',
'delegation.child1': 'child1_id',
}
child0_id = fields.Many2one('delegation.child0', required=True, ondelete='cascade')
child1_id = fields.Many2one('delegation.child1', required=True, ondelete='cascade')
#use
env = self.env
record = env['delegation.parent'].create({
'child0_id': env['delegation.child0'].create({'field_0': 0}).id,
~~~
## Domain表達式
domain表達式是由多個(field_name, operator, value)元組構成的列表或數組
> field_name -- 字段名或者用.號分隔的Many2one關系的字段如:'street' , 'partner_id.country'
> operator(str) -- 用于對字段值和給定值進行比較的運算符:
>
> > =,!=,>,>=,<,<=,
> > =?(值為false或none時返回true,否則與=效果一致)
> > =like()將字段數據與value進行匹配,_代表匹配單個字符、%匹配0或多個字符
> > like() 將字段數據與%value% 進行匹配,
> > not like 不與%value%匹配
> > ilike 忽略大小寫的like函數
> > not ilike 忽略大小寫的not like
> > =ilike 忽略大小寫的=like
> > in 與value的任意值相等,value須為值列表
> > not in 與value的任意值都不相等
> > child_of 是否由value派生而來
>
> value 對應值,必須與相應條件對應
>
> > 多個domain表達式可用運算符進行連接,運算符寫在兩個表達式之前。
> >
> > > & 邏輯與 ,| 邏輯或,!邏輯非
~~~
#例:
[('name','=','ABC'),
('language.code','!=','en_US'),
'|',('country_id.code','=','be'),
('country_id.code','=','de')]
~~~
## Porting from the old API to the new API
這個基本不需要用
* * *
譯自odoo官方文檔:[http://www.odoo.com/documentation/10.0/reference/orm.html,不當之處歡迎批評指正。](http://www.odoo.com/documentation/10.0/reference/orm.html%EF%BC%8C%E4%B8%8D%E5%BD%93%E4%B9%8B%E5%A4%84%E6%AC%A2%E8%BF%8E%E6%89%B9%E8%AF%84%E6%8C%87%E6%AD%A3%E3%80%82)
* * *
*內容發布自[http://www.jianshu.com/u/6fdae8ec06bc](http://www.jianshu.com/u/6fdae8ec06bc),轉載請注明出處*
作者:湖南玖零網絡科技
鏈接:http://www.jianshu.com/p/88f6f79756be
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
- 開發教程
- Odoo10開發教程一(構建模塊)
- Odoo10開發教程二(基本視圖)
- Odoo10開發教程三(模型關聯)
- Odoo10開發教程四(繼承)
- Odoo10開發教程五(計算字段和默認值)
- Odoo10開發教程六(高級視圖)
- Odoo10開發教程七(工作流和安全)
- 參考手冊
- odoo V10中文參考手冊(一:ORM API)
- odoo V10中文參考手冊(指導規范)
- 技巧
- odoo 常用widget
- Odoo(OpenERP)開發實踐:菜單隱藏(1)
- Odoo(OpenERP)開發實踐:菜單隱藏(2)
- Odoo(OpenERP)開發實踐:數據模型學習
- Odoo中自動備份數據庫
- Odoo(OpenERP)應用實踐: 使用db-filter參數實現通過域名指定訪問哪個數據庫
- Odoo(OpenERP)配置文件openerp-server.conf詳解
- Odoo(OpenERP v8)數據模型(Data Model)
- odoo10學習筆記十七:controller
- Qweb定義