现在的Odoo是从就的(不规律的)API过渡来的,它可能需要从一个手动桥接到另一个手动桥接:
新旧AIP间一个最大的问题是:
ids
)被显式地传递给方法,也可能根本就没有传递默认情况下, 方法被假定为使用新的API风格,并且不能从旧api样式调用。
提示
从新API到旧API的调用是桥接的
当使用新API样式时,对使用旧API定义的方法的调用将自动转换,不需要做任何特殊的事情:
>>> # method in the old API style
>>> def old_method(self, cr, uid, ids, context=None):
... print ids
>>> # method in the new API style
>>> def new_method(self):
... # system automatically infers how to call the old-style
... # method from the new-style method
... self.old_method()
>>> env[model].browse([1, 2, 3, 4]).new_method()
[1, 2, 3, 4]
两个修饰符可以暴露旧的API的新型的方法:
model()
该方法暴露不使用ids,它的记录集一般的空集合。它的“旧的API”的签名是cr, uid, *arguments, context
:
@api.model
def some_method(self, a_value):
pass
# can be called as
old_style_model.some_method(cr, uid, a_value, context=context)
multi()
该方法暴露使用一个id列表(可能是空的),它的“旧的API”的签名是cr, uid, ids, *arguments, context
:
@api.multi
def some_method(self, a_value):
pass
# can be called as
old_style_model.some_method(cr, uid, [id1, id2], a_value, context=context)
由于新型API会返回记录集和旧的API会返回一个id的列表,还有一个修饰符处理这个:
returns()
功能是返回一个记录集,第一个参数应该是记录集模型或者记录集本身(self)的名字(针对当前模型)。
如果在新的API风格下调用方法是无效的,但是当使用就的API风格调用则将会把记录集转换为id的列表:
>>> @api.multi
... @api.returns('self')
... def some_method(self):
... return self
>>> new_style_model = env['a.model'].browse(1, 2, 3)
>>> new_style_model.some_method()
a.model(1, 2, 3)
>>> old_style_model = pool['a.model']
>>> old_style_model.some_method(cr, uid, [1, 2, 3], context=context)
[1, 2, 3]
class odoo.models.Model(pool, cr)
作为常规的数据库持久的Odoo模型最主要的超类。
Odoo模型冲这个超类集成创建:
class user(Model):
...
系统稍后将对每个数据库(在安装的类模块上)实例化一次类。
_name
业务对象名称,用点表示法(在模块命名空间中)
_rec_name
作为名称使用的备选字段,被osv的name_get()方法使用 (默认: 'name'
)
_inherit
_name
属性设置了值,继承父模型的名称。如果从单个父模型继承,可以是一个str
_name
属性没有设置值, 扩展单一模型的名称详见继承与扩展(odoo10系列--ORM API 三 )
_order
没有指定顺序搜索时的有序字段 (默认: 'id'
)
类型 str
_auto
一个数据库表是否应该被创建 (默认值:
True
)如果设置了
False
, 重写init()
方法去创建数据库表
提示
创建一个没有任何数据库表的模型,继承自 odoo.models.AbstractModel
_table
当_auto
为true,支持创建模型的数据库表名称, 默认情况下自动生成
_inherits
字典映射的父业务对象的_name到相应外键字段名称的使用:
_inherits = {
'a.model': 'a_field_id',
'b.model': 'b_field_id'
}
实现基于组成的继承:新模型暴露了_inherits
-ed(继承的)模型上所有的字段但是不保存这些字段: 值本身仍然存储在链接的记录中
警告
如果同一字段定义在多个_inherits
-ed(继承的)字段中
_constraints
(constraint_function, message, fields)
列表定义了Python约束。 字段列表是指示性的
自版本8.0后过时:使用constrains()
_sql_constraints
(name, sql_definition, message)
元组列表在生成支持表时定义要执行的SQL约束
_parent_store
Alongside parent_left
and parent_right
, 设置一个嵌套的集合在当前模型的记录中启用快速分层查询(默认: False
)
类型 bool
create(vals) → record
为对模型创建一个新记录。
新记录使用来自vals的值进行初始化且有必要时使用来自default_get()
方法的值初始化
参数
vals (dict
) --
模型字段的值作为一个字典:
{'field_name': field_value, ...}
详见write()
了解详细信息
返回
创建一个新记录
异常
browse([ids]) → records
为作为当前环境参数而提供的id列表返回一个记录集。
可以没有id,一个id或者id序列
unlink()
删除当前集合的
异常
write(vals)
使用提供的值更新当前集合的所有记录
参数
vals (dict
) --
要更新的字段及其设置的值,例如:
{'foo': 1, 'bar': "Qux"}
将设置字段foo
为 1
并设置字段bar
为"Qux"
,如果它们是有效的(否则将触发一个错误)
异常
Integer
, Float
) ,值应该是相应类型的值Boolean
, 值应该是一个 bool
Selection
, 该值应与选择值(通常是str
,有时为int
)匹配Many2one
, 该值应该是要设置的记录的数据库标识符其他非关系字段使用字符串作为值
危险
由于历史和兼容性的原因, Date
和Datetime
字段使用字符串作为值(写入和读取) 而不是date
或者datetime
.这些日期字符串仅是UTC格式并通过odoo.tools.misc.DEFAULT_SERVER_DATE_FORMAT
和odoo.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
格式化
One2many
和Many2many
字段使用一种特殊的“命令”格式的操作记录存储在与该领域相关的设置。
这种格式是按顺序执行的三个一组的列表,其中每一个三元组是在一组记录上执行的命令。并非所有命令都适用于所有情况。可能的命令是:
(0, _, values)
从提供的字典value中,增加一个新创建的记录
(1, id, values)
使用在values中的值更新现存的编号为id的记录。不能在create()
中使用
(2, id, _)
从集合中删除编号为id
的记录,然后删除它(从数据库中)。 不能在create()
中使用
(3, id, _)
从集合中删除编号为id的记录,但不能删除它。不能在中使用。不能在create()
中使用
(4, id, _)
添加现有编号id为的记录到集合中。不能在中使用.
(5, _, _)
从集合中删除所有记录,相当于显示的在每个记录上使用命令 3
。 不能在
中使用。不能在One2many
create()
中使用
(6, _, ids)
通过ids列表替换集合中所有现有的记录,相当于在中ids的每个id上使用命令5
随和使用命令 4
注
以上列表中标记为_的值将被忽略,也可能是任何值,一般为 0
或者 False
read([fields])
读取self,低级/RPC方法中的记录记录的请求字段。在Python代码中则使用browse()
方法
参数
fields -- 要返回的字段名称列表(默认是所有字段)
返回
将字段名映射到其值的字典列表,每个记录有一个字典
异常
AccessError -- 如果用户对某些给定的记录没有读权限
read_group(domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
获取由给定groupby字段分组的列表视图中的记录列表
参数
list
) -- 对象上指定的列表视图中呈现的字段列表list
) -- 通过描述列表的记录将被分组。一个分组描述要么是个字段(然后它将被该字段分组)要么是一个字符串'field:groupby_function'。目前, 唯一支持的功能是'day', 'week', 'month', 'quarter' 或'year', 并且他们仅对date/datetime字段是有意义的int
) -- 可跳过的可选记录数int
) -- 可返回的可选最大记录数list
) -- 可选的order by
规范, 为重写组分类的自然分类,也可详见 search()
(目前仅支持many2one字段)bool
) -- 如果为true, 结果仅靠groupby参数列表中第一个值进行分组,并且groupby参数列表中剩余的值将被放到__context键中。如果为false, 所有groupby参数列表中的值在一次调用中处理返回
字典列表(每个记录有一个字典) ,包含一下内容:
groupby
论点中字段进行分组的字段值返回类型
[{'field_name_1': value, ...]
异常
AccessError --
search(args[, offset=0][, limit=None][, order=None][, count=False])
基于args的搜索域搜索记录
参数
int
) -- 忽略的结果数 (默认: none)int
) -- 返回的最大记录数 (默认: all)str
) -- 排序字符串bool
) -- 如果为true,只计算并返回匹配记录的数量 (默认: False)返回
至多匹配搜索条件的limit记录
异常
AccessError --
search_count(args) → int
返回匹配当前域的当前模型中的记录数
name_search(name='', args=None, operator='ilike', limit=100) → records
搜索记录,这些记录有一个显示的名称,当和给定操作符operator比较时匹配给定name模式,同时也匹配可选的搜索域(args
)。
例如,它用于根据关系字段的部分值提供建议。有时被视为name_get()
方法的逆函数,但它不能保证。
这种方法相当于调用一个基于display_name的一个搜索域的search()
方法,然后name_get()
在搜索结果上
参数
str
) -- 要匹配的名称模式list
) -- 指定进一步的限制的可选的搜索域(详见search()
语法)str
) -- 匹配name的域操作符, 例如'like'
或 '='
.int
) -- 可返回的可选最大记录数返回类型
列表
返回
所有匹配记录的(id, text_repr)
对列表
ids
在这个记录集中实际记录id列表(忽略创建记录的的占位id)
ensure_one()
验证当前记录集是否仅有单个记录。否则抛出异常
exists() → records
返回存在self中的记录中的子集,并在缓存中标记已删除的记录。它可以用作记录的测试:
if record.exists():
...
按照惯例,新记录将作为已存在的返回
filtered(func)
选择self
中的记录这样其 func(rec)
是真实的, 并将其作为一个记录集
参数
func -- 字段名称的函数或字段名称的点分隔序列
sorted(key=None, reverse=False)
返回记录集 self
排序的 key
.
参数
True
, 以相反的顺序返回结果mapped(func)
适用于在self中所有记录的func
, 并作为一个列表或记录集返回结果(如果 func
返回记录集)。 在后一种情况下,返回的记录集的顺序是任意的
参数
func -- 一个函数或一个圆点分隔的字段名序列(字符串); 任何临时的值只返回记录集self
sudo([user=SUPERUSER])
返回一个新的记录集版本连接到提供用户
默认返回一个访问控制和记录规则绕过SUPERUSER记录集
注
使用sudo可能导致跨记录规则边界的数据访问,可能混合就意味着被孤立的记录(如记录多公司环境的不同公司)
这可能会导致在许多记录中选择一个记录——例如获得默认的公司,或选择物料清单的方法——产生不直观的结果
注
因为记录和访问控制规则会被重新评估,新的记录将无法从当前的环境的数据缓存处收益,所以后来的数据访问可能招致额外的延迟而从数据库重新读取。返回的记录集具有相同的预取对象为self
.
with_context([context][, **overrides]) → records
返回一个新的记录集版本连接到可扩展的上下文
扩展上下文要么是被合并overrides的context,要么是合并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)
返回一个新的记录集版本连接到提供的环境
警告
新的环境将无法从当前的环境的数据缓存处收益,所以后来的数据访问可能招致额外的延迟而从数据库重新读取。返回的记录集具有相同的预取对象为self
fields_get([fields][, attributes])
返回每个字段的定义。
返回值是一个字典(由字段名诱导)字典。 _inherits字段包括在其中。string, help, and selection(如果存在)属性被翻译
参数
fields_view_get([view_id | view_type='form'])
获取所请求的视图的详细组成,如字段、模型、视图体系结构
参数
返回
描述所请求视图(包括继承视图和扩展)的组成的字典
异常
default_get(fields) → default_values
为fields_list中的字段返回默认值。默认值由上下文、默认用户和模型本身决定
参数
fields_list -- 字段名称列表
返回
一个字典将每个字段名映射到对应的默认值,如果它有一个
copy(default=None)
复制以默认值self更新的记录
参数
default (dict
) -- 字段值字典以覆盖复制记录的原始值, 例如: {'field_name': overridden_value, ...}
返回
新记录
name_get() → [(id, name), ...]
返回self中记录的文本表示形式。默认情况下这是display_name字段的值
返回
每个记录的(id, text_repr)对列表
返回类型
列表(元组)
name_create(name) → record
通过使用仅有一个参数的create()
方法创建一个新的记录: 新记录的显示名称。
新记录将以适用于该模型的默认值初始化,也可以通过上下文提供。 对create()
通常的行为适用
参数
name -- 显示要创建的记录的名称
返回类型
元组
返回
所创建的记录的name_get()
成对值
id
field
标识符
_log_access
是否应该生成(默认: True
)日志访问的字段(create_date
, write_uid
, ...)
create_date
创建记录的日期
类型 Datetime
create_uid
创建记录的用户的关系字段
类型 res.users
write_date
最新记录修改的日期
类型 Datetime
write_uid
修改记录的最后一个用户的关系字段
类型 res.users
一些字段名称保留在自动字段之外的预定义行为中。当需要相关行为时,应该在模型上定义它们:
name
作为_rec_name
默认值 , 用于在具有代表性“命名”是必须的上下文中显示记录
类型 Char
active
切换全局显示的记录,如果active
被设置为False
,记录在大多的查询和列表中不可见
类型 Boolean
sequence
可变的排序标准,允许在列表视图中对模型进行拖放重新排序
类型 Integer
state
对象的生命周期阶段,由fields
上的states属性使用
类型 Selection
parent_id
用于在树结构中排序记录并在域中启用child_of操作符
类型 Many2one
parent_left
使用_parent_store
,允许更快速的访问树结构
parent_right
详见 parent_left
此模块提供管理两种不同API风格的元素,即“传统”和“记录”风格。
在“传统”的风格中,像数据库游标,用户ID,上下文词典和记录ID(通常表示为cr
, uid
, context
, ids
)这样的参数是显式传递给所有方法的。 在“记录”的风格中,这些参数是隐藏在模型的实例,这使得它更加面向对象的感觉
例如,语句:
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)
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)
self中修饰记录风格的方法是一个记录集,但它的内容是不相关的,只有模型是相关的。方法如下:
@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)
返回指定“计算”方法字段依赖项的装饰器(对于新风格的函数字段)。每个参数必须是一个字符串,它包含一个点分隔的字段名称序列:
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
异常
警告
@constrains
仅仅支持简单字段名称,带点的名字 (关联字段的字段,例如 partner_id.customer
) 是不支持的且将被忽略
只有修饰的方法中的修饰字段包含在create
方法或write方法调用中时@constrains
将触发。 它意味着视图中不存在的字段不会在记录创建期间触发调用。为了确保约束始终被触发(例如为了检验值的缺失),需要重写 create
方法
odoo.api.onchange(*args)
返回一个装饰符去修饰给定字段的onChange方法。每个参数必须是字段名:
@api.onchange('partner_id')
def _onchange_partner(self):
self.message = "Dear %s" % (self.partner_id.name or "")
在字段显示的表单视图中,当某个给定字段被修改时,将调用该方法。该方法在包含该表单中的值的伪记录上调用。 该记录上的字段分配将自动返回给客户端。
该方法可以返回一个改变字段域的字典和弹出一个警告信息,如旧的API:
return {
'domain': {'other_id': [('partner_id', '=', partner_id)]},
'warning': {'title': "Warning", 'message': "What is this?"},
}
警告
@onchange
仅仅支持简单字段名称,带点的名字 (关联字段的字段,例如 partner_id.tz
) 是不支持的且将被忽略
odoo.api.returns(model, downgrade=None, upgrade=None)
返回用于返回model实例的方法的装饰器
参数
'self'
downgrade(self, value, *args, **kwargs)
函数将记录风格的value
转换为传统风格输出upgrade(self, value, *args, **kwargs)
函数将传统风格value
转换为记录风格输出参数 self
, *args
and **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)
请注意,装饰方法必须符合惯例
这些装饰都自动继承: 重写装饰现有方法的方法将使用同一个 @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()
且无论是在self记录集上迭代或使用ensure_one()
确认记录集是单个记录
odoo.api.v7(method_v7)
只装饰支持旧样式API的方法。 一种新样式的API可以通过重新定义的具有相同的名字和使用v8()
装饰的方法来提供:
@api.v7
def foo(self, cr, uid, ids, context=None):
...
@api.v8
def foo(self):
...
如果一个方法调用另一个方法,必须特别小心,因为方法可能被重写! 在这种情况下,方法应该从目前的类调用方法(比如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)
只支持一种新型api的方法。一种旧样式的API可以通过重新定义的具有相同的名字和使用装饰的方法来提供:
@api.v8
def foo(self):
...
@api.v7
def foo(self, cr, uid, ids, context=None):
...
注意封装方法使用第一种方法的文档字符串
ps:有翻译不当之处,欢迎留言指正。
原文地址:https://www.odoo.com/documentation/10.0/reference/orm.html