odoo10参考系列--ORM API 二(新旧API兼容性、模型参考和方法修饰符)

新API与旧API的兼容性

现在的Odoo是从就的(不规律的)API过渡来的,它可能需要从一个手动桥接到另一个手动桥接:

  • RPC层(XML-RPC和RPC)是在旧的API的形式表达,表达的纯粹的方法在新的API中不可用在RPC
  • 可重写的方法可以从仍然用旧的API风格编写的旧的代码段中调用

新旧AIP间一个最大的问题是:

  • 环境(Environment)值(游标、用户ID和上下文)显式地传递给方法
  • 记录数据(ids)被显式地传递给方法,也可能根本就没有传递
  • 方法往往倾向于在id列表上而不是记录集上工作

默认情况下, 方法被假定为使用新的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(poolcr)

作为常规的数据库持久的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

CRUD(创建、读取、更新和删除)

create(vals) → record

为对模型创建一个新记录。

新记录使用来自vals的值进行初始化且有必要时使用来自default_get()方法的值初始化

参数

vals (dict) --

模型字段的值作为一个字典:

{'field_name': field_value, ...}

详见write() 了解详细信息

返回

创建一个新记录

异常

  • AccessError --
    • 如果用户对请求对象没有创建权限
    • 如果用户试图绕过在请求对象上创建的访问规则
  • ValidateError -- 如果用户试图为未选择的字段输入无效值
  • UserError -- 如果在操作结果对象的层次结构中创建一个循环 (例如将对象设置为自己的父对象)

browse([ids]) → records

为作为当前环境参数而提供的id列表返回一个记录集。

可以没有id,一个id或者id序列

unlink()

删除当前集合的

异常

  • AccessError --
    • 如果用户对请求对象没有删除权限
    • 如果用户试图绕过请求对象的删除规则
  • UserError -- 如果记录默认是其他记录的属性

write(vals)

使用提供的值更新当前集合的所有记录

参数

vals (dict) --

要更新的字段及其设置的值,例如:

{'foo': 1, 'bar': "Qux"}

将设置字段foo 为 1 并设置字段bar 为"Qux" ,如果它们是有效的(否则将触发一个错误)

异常

  • AccessError --
    • 如果用户对请求对象没有更新权利
    • 如果用户试图绕过请求对象的更新规则
  • ValidateError -- 如果用户试图为未选择的字段输入无效值
  • UserError -- 如果在操作结果对象的层次结构中创建一个循环 (例如将对象设置为自己的父对象)
  • 对于数值字段(IntegerFloat) ,值应该是相应类型的值
  • 对于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(domainfieldsgroupbyoffset=0limit=Noneorderby=Falselazy=True)

获取由给定groupby字段分组的列表视图中的记录列表

参数

  • domain -- 指定搜索条件的列表 [['field_name', 'operator', 'value'], ...]
  • fields (list) -- 对象上指定的列表视图中呈现的字段列表
  • groupby (list) -- 通过描述列表的记录将被分组。一个分组描述要么是个字段(然后它将被该字段分组)要么是一个字符串'field:groupby_function'。目前, 唯一支持的功能是'day', 'week', 'month', 'quarter' 或'year', 并且他们仅对date/datetime字段是有意义的
  • offset (int) -- 可跳过的可选记录数
  • limit (int) -- 可返回的可选最大记录数
  • orderby (list) -- 可选的order by 规范, 为重写组分类的自然分类,也可详见 search() (目前仅支持many2one字段)
  • lazy (bool) -- 如果为true, 结果仅靠groupby参数列表中第一个值进行分组,并且groupby参数列表中剩余的值将被放到__context键中。如果为false, 所有groupby参数列表中的值在一次调用中处理

返回

字典列表(每个记录有一个字典) ,包含一下内容:

  • 依靠 groupby 论点中字段进行分组的字段值
  • __domain: 指定搜索条件的元组列表
  • __context: 带有像groupby一样论点的字典

返回类型

[{'field_name_1': value, ...]

异常

AccessError --

  • 如果用户在所请求的对象上没有读权限
  • 如果用户试图绕过在被请求对象上读取的访问规则

搜索

search(args[, offset=0][, limit=None][, order=None][, count=False])

基于args的搜索域搜索记录

参数                 

  • args -- 一个搜索域。使用空列表匹配所有记录
  • offset (int) -- 忽略的结果数 (默认: none)
  • limit (int) -- 返回的最大记录数 (默认: all)
  • order (str) -- 排序字符串
  • count (bool) -- 如果为true,只计算并返回匹配记录的数量 (默认: False)

返回

至多匹配搜索条件的limit记录

异常

AccessError --

  • 如果用户试图绕过在被请求对象上读取的访问规则

search_count(args) → int

返回匹配当前域的当前模型中的记录数

name_search(name=''args=Noneoperator='ilike'limit=100) → records

搜索记录,这些记录有一个显示的名称,当和给定操作符operator比较时匹配给定name模式,同时也匹配可选的搜索域(args)。

例如,它用于根据关系字段的部分值提供建议。有时被视为name_get()方法的逆函数,但它不能保证。

这种方法相当于调用一个基于display_name的一个搜索域的search()方法,然后name_get()在搜索结果上

参数

  • name (str) -- 要匹配的名称模式
  • args (list) -- 指定进一步的限制的可选的搜索域(详见search() 语法)
  • operator (str) -- 匹配name的域操作符, 例如'like' 或 '='.
  • limit (int) -- 可返回的可选最大记录数

返回类型

列表

返回

所有匹配记录的(id, text_repr) 对列表

记录集操作

ids

在这个记录集中实际记录id列表(忽略创建记录的的占位id)

ensure_one()

验证当前记录集是否仅有单个记录。否则抛出异常

exists() → records

返回存在self中的记录中的子集,并在缓存中标记已删除的记录。它可以用作记录的测试:

if record.exists():
    ...

按照惯例,新记录将作为已存在的返回

filtered(func)

选择self 中的记录这样其 func(rec)是真实的, 并将其作为一个记录集

参数

func -- 字段名称的函数或字段名称的点分隔序列

sorted(key=Nonereverse=False)

返回记录集 self 排序的 key.

参数

  • key -- 一个参数的函数,它为每个记录返回一个比较键,或者一个字段名,或者None,在这种情况下,记录是根据默认模型的顺序来排序的
  • reverse -- 如果True, 以相反的顺序返回结果

mapped(func)

适用于在self中所有记录的func, 并作为一个列表或记录集返回结果(如果 func 返回记录集)。 在后一种情况下,返回的记录集的顺序是任意的

参数

func -- 一个函数或一个圆点分隔的字段名序列(字符串); 任何临时的值只返回记录集self

环境交换

 

 

 

sudo([user=SUPERUSER])

返回一个新的记录集版本连接到提供用户

默认返回一个访问控制和记录规则绕过SUPERUSER记录集

使用sudo可能导致跨记录规则边界的数据访问,可能混合就意味着被孤立的记录(如记录多公司环境的不同公司)

这可能会导致在许多记录中选择一个记录——例如获得默认的公司,或选择物料清单的方法——产生不直观的结果

因为记录和访问控制规则会被重新评估,新的记录将无法从当前的环境的数据缓存处收益,所以后来的数据访问可能招致额外的延迟而从数据库重新读取。返回的记录集具有相同的预取对象为self.

with_context([context][, **overrides]) → records

返回一个新的记录集版本连接到可扩展的上下文

扩展上下文要么是被合并overridescontext,要么是合并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(如果存在)属性被翻译

参数

  • allfields -- 文档字段列表,全部为空或不提供
  • attributes -- 为每个字段返回的描述属性列表,全部为空或未提供

fields_view_get([view_id | view_type='form'])

获取所请求的视图的详细组成,如字段、模型、视图体系结构

参数

  • view_id -- 视图的id或者没有
  • view_type -- 值是None则返回视图的类型 ('form', 'tree', ...)
  • toolbar -- 为true则包含上下文操作
  • submenu -- 过时的

返回

描述所请求视图(包括继承视图和扩展)的组成的字典

异常

  • AttributeError --
    • 如果继承的视图具有未知的位置,则与除'before', 'after', 'inside', 'replace'外值一起工作
    • 如果在父视图中找到了“位置”以外的标记
  • Invalid ArchitectureError -- 如果在结构上定义了视图类型,而不是表单、树、日历、搜索等

不同的方法

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_datewrite_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(通常表示为cruidcontextids)这样的参数是显式传递给所有方法的。 在“记录”的风格中,这些参数是隐藏在模型的实例,这使得它更加面向对象的感觉

例如,语句:

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(modeldowngrade=Noneupgrade=None)

返回用于返回model实例的方法的装饰器

参数

  • model -- 一个模型名称,或当前模型的 'self'
  • downgrade -- 一个 downgrade(self, value, *args, **kwargs) 函数将记录风格的value 转换为传统风格输出
  • upgrade -- 一个upgrade(self, value, *args, **kwargs) 函数将传统风格value 转换为记录风格输出

参数 self*args and **kwargs在记录风格中传递给方法的。

装饰器将方法输出调整到API样式:idids 或 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

你可能感兴趣的:(odoo,架构及框架)