odoo12 ORM API 翻译

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_41317565/article/details/86612227

记录

版本8.0中的新功能:此页面记录了Odoo 8.0中添加的新API,它应该是未来的主要开发API。它还提供了有关从版本7及更早版本的“旧API”移植或桥接的信息,但未明确记录该API。请参阅旧文档。

与模型和记录的交互是通过记录集执行的,记录集是同一模型的有序记录集。

警告
与名称所暗示的相反,目前记录集可能包含重复项。这可能在将来发生变化。

模型上定义的方法在记录集上执行,它们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()

迭代记录集将产生新的单个记录集 (“单例”),就像迭代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), ...

现场访问

记录集提供“活动记录”界面:模型字段可以作为属性直接从记录中读取和写入,但仅限于单个记录(单记录记录集)。字段值也可以像dict项一样访问,这比getattr()动态字段名称更优雅,更安全。设置字段的值会触发对数据库的更新:

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

尝试在多个记录上读取或写入字段会引发错误。

访问关系字段(Many2one, One2many,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.name             # first access reads value from database
record.name             # second access gets value from cache

为了避免一次在一条记录上读取一个字段,Odoo会根据一些启发式方法预取记录和字段以获得良好的性能。一旦必须在给定记录上读取字段,ORM实际上会在较大的记录集上读取该字段,并将返回的值存储在缓存中供以后使用。预取记录集通常是记录集,记录来自迭代。此外,所有简单的存储字段(布尔,整数,浮点数,字符,文本,日期,日期时间,选择,许多2)都被完全取出; 它们对应于模型表的列,并在同一查询中有效获取。

请考虑以下示例,其中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

预取也适用于辅助记录:当读取关系字段时,它们的值(即记录)被预订以供将来预取。访问其中一个辅助记录会预取同一模型中的所有辅助记录。这使得以下示例仅生成两个查询,一个用于合作伙伴,一个用于国家/地区:

countries = set()
for partner in partners:
    country = partner.country_id        # first pass prefetches all partners
    countries.add(country.name)         # first pass prefetches all countries

设置操作

记录集是不可变的,但可以使用各种set操作组合相同模型的集合,返回新的记录集。设置操作不会 保留顺序。

record in set返回是否存在record(必须是1元素记录集)set。record not in set是逆操作
set1 <= set2并set1 < set2返回是否set1是set2(resp严格)的子集
set1 >= set2并set1 > set2返回是否set1是set2(resp严格)的超集
set1 | set2 返回两个记录集的并集,一个包含任一源中存在的所有记录的新记录集
set1 & set2 返回两个记录集的交集,一个新记录集仅包含两个源中存在的记录
set1 - set2返回一个包含只记录一个新的记录set1 ,其是不是在set2

其他记录集操作

记录集是可迭代的,因此普通的Python工具可用于转化(map(),sorted(), itertools.ifilter,…),但是这些返回一个 list或一个迭代器,删除调用他们的结果的方法,或用一组操作的能力。

因此,记录集提供这些操作返回记录集本身(如果可能):

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()
返回按提供的键函数排序的记录集。如果未提供密钥,请使用模型的默认排序顺序:

# 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')

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

环境

在Environment由ORM用于存储各种上下文数据:数据库光标(数据库查询),当前用户(访问权限检查)和当前的上下文(存储任意元数据)。环境还存储缓存。

所有记录集都有一个不可变的环境,可以使用env它来访问,并提供对当前user(user),cursor(cr)或context(context)的访问:

>>> records.env
<Environment object ...>
>>> records.env.user
res.user(3)
>>> records.env.cr
<Cursor object ...)

从其他记录集创建记录集时,将继承环境。环境可用于在其他模型中获取空记录集,并查询该模型:

>>> self.env['res.partner']
res.partner
>>> 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()
可以采用单个位置参数,它替换当前环境的上下文
可以通过关键字获取任意数量的参数,这些参数被添加到当前环境的上下文或步骤1中设置的上下文中

# look for partner, or create one with specified timezone if none is
# found
env['res.partner'].with_context(tz=a_tz).find_or_create(email_address)

with_env()
完全取代现有环境

常见的ORM方法

search()
采用搜索域,返回匹配记录的记录集。可以返回匹配记录(offset 和limit参数)的子集并进行排序(order参数):

>>> # searches the current model
>>> 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': "Joe"})
res.partner(78)
>>> self.create([{'name': "Jack"}, {'name': "William"}, {'name': "Averell"}])
res.partner(79, 80, 81)

了解如何使用一个API或另一个API定义方法create

write()
获取许多字段值,将它们写入其记录集中的所有记录。不归还任何东西:

self.write({'name': "Newer Name"})

browse()
获取数据库ID或id列表并返回记录集,当从外部Odoo获取记录ID(例如,通过外部系统往返)或在旧API中调用方法时非常有用:

>>> 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()
环境方法返回与提供的外部id匹配的记录 :

>>> env.ref('base.group_public')
res.groups(2)

ensure_one()
检查记录集是否为单例(仅包含单个记录),否则会引发错误:

records.ensure_one()
# is equivalent to but clearer than:
assert len(records) == 1, "Expected singleton"

创建模型

模型字段定义为模型本身的属性:

from odoo import models, fields
class AModel(models.Model):
    _name = 'a.model.name'

    field1 = fields.Char()

警告
这意味着您无法定义具有相同名称的字段和方法,它们会发生冲突

默认情况下,字段的标签(用户可见名称)是字段名称的大写版本,可以使用以下string参数覆盖:

field2 = fields.Integer(string="an other field")

有关各种字段类型和参数,请参阅字段参考。

默认值定义为字段上的参数,值为:

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

使用子字段时,依赖关系可以是虚线路径:

@api.depends('line_ids.value')
def _compute_total(self):
    for record in self:
        record.total = sum(line.value for line in record.line_ids)

默认情况下不会存储计算字段,它们会在请求时计算并返回。设置store=True会将它们存储在数据库中并自动启用搜索
也可以通过设置search 参数来启用在计算字段上搜索。该值是返回域的方法名称 :

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)]

要允许在计算字段上设置值,请使用该inverse 参数。它是反转计算和设置相关字段的函数的名称:

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)

可以通过相同的方法同时计算多个字段,只需在所有字段上使用相同的方法并设置所有字段:

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

相关领域
计算字段的特殊情况是相关(代理)字段,其提供当前记录上的子字段的值。它们是通过设置related参数来定义的,就像它们可以存储的常规计算字段一样:

nickname = fields.Char(related='user_id.partner_id.name', store=True)

onchange:动态更新UI

当用户更改表单中的字段值(但尚未保存表单)时,根据该值自动更新其他字段可能很有用,例如,当税收更改或新发票行更新时更新最终总计添加。

计算字段会自动检查并重新计算,它们不需要 onchange
对于非计算字段,onchange()装饰器用于提供新的字段值:

@api.onchange('field1', 'field2') # if these fields are changed, call method
def check_change(self):
    if self.field1 < self.field2:
        self.field3 = True

然后,在方法期间执行的更改将发送到客户端程序并对用户可见

客户端自动调用计算字段和new-API onchanges,而无需在视图中添加它们
可以通过on_change="0"在视图中添加来禁止来自特定字段的触发器 :

<field name="name" on_change="0"/>

当用户编辑字段时,即使有功能字段或显式onchange取决于该字段,也不会触发任何接口更新。

onchange 方法对虚拟记录的工作分配这些记录不会写入数据库,只是用于知道要将哪个值发送回客户端

警告
a one2many或many2manyfield 不可能通过onchange修改自身。这是webclient限制 - 请参阅#2693。

低级SQL

在cr上的环境属性是光标用于当前数据库事务,并允许直接执行的SQL,无论是对查询其难以用ORM来表达(例如复杂的连接),或者出于性能的原因:

self.env.cr.execute("some_sql", param1, param2, param3)

由于模型使用相同的游标并Environment 保存各种缓存,因此在原始SQL中更改数据库时,这些缓存必须无效,否则模型的进一步使用可能会变得不连贯。在使用时CREATE,UPDATE或DELETE在SQL中,有必要清除缓存,而不是SELECT(只是读取数据库)。

可以使用对象的invalidate_cache()方法 来执行清除缓存 BaseModel。

新API和旧API之间的兼容性

Odoo目前正在从较旧(较不常规)的API转换,可能需要手动从一个API手动桥接到另一个:

RPC层(XML-RPC和JSON-RPC)都是用旧API表示的,纯粹在新API中表示的方法不能通过RPC获得
可以从仍旧用旧API样式编写的旧代码片段调用可覆盖的方法
旧API和新API之间的巨大差异是:

的值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()
该方法暴露为不使用id,其记录集通常为空。它的“旧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)

请注意,使用单个字典始终会调用create装饰的方法model()。将始终create使用变量model_create_multi()列表调用使用变量修饰 的方法。装饰器负责将参数转换为一种形式或另一种形式:

@api.model
def create(self, vals):
    ...

@api.model_create_multi
def create(self, vals_list):
    ...

因为新式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从单个父级继承的if
如果_name未设置,则将单个模型的名称扩展到原位
请参见继承和扩展。

_order
没有指定的顺序进行搜索时订购场(默认: ‘id’)

类型 海峡
_auto
无论是数据库表应创建(默认值:True)

如果设置为False,则覆盖init()以创建数据库表

要创建没有任何表的模型,请继承 odoo.models.AbstractModel

_table
支持创建模型的表的名称, _auto默认情况下自动生成。

_inherits
将父业务对象的_name映射到要使用的相应外键字段的名称的字典:

    '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
除了一个parent_path领域,建立记录的树结构的索引存储,以使当前模型的使用记录速度更快层次查询child_of和 parent_of域运营商。(默认值:False)

类型 布尔
CRUD
create(vals_list) → records
为模型创建新记录。

新记录使用dicts列表中的值进行初始化 vals_list,如果需要,可以使用default_get()。

参数 vals_list(list) -
模型字段的值,作为字典列表:

[{ ‘field_name’ : field_value , … }, … ]
为了向后兼容,vals_list可能是字典。它被视为单例列表[vals],并返回单个记录。

看write()详情

返回 创建的记录
加薪
AccessError -
如果用户对请求的对象没有创建权限
如果用户尝试绕过请求对象上的create的访问规则
ValidateError - 如果用户尝试为不在选择中的字段输入无效值
UserError - 如果在对象层次结构中创建循环操作的结果(例如将对象设置为其自己的父对象)
browse([ids]) → records
返回当前环境中作为参数提供的ID的记录集。

不能使用任何ID,单个ID或一系列ID。

unlink()
删除当前集的记录

加薪
AccessError -
如果用户对请求的对象没有取消链接权限
如果用户试图绕过请求对象上取消链接的访问规则
UserError - 如果记录是其他记录的默认属性
write(vals)
使用提供的值更新当前集中的所有记录。

参数 vals(dict) -
要更新的字段和要在其上设置的值,例如:

{ 'foo'1'bar' : “Qux” }

将字段设置foo为1和字段bar为 "Qux"if如果它们是有效的(否则它将触发错误)。

加薪
AccessError -
如果用户对请求的对象没有写权限
如果用户试图绕过访问规则以写入所请求的对象
ValidateError - 如果用户尝试为不在选择中的字段输入无效值
UserError - 如果在对象层次结构中创建循环操作的结果(例如将对象设置为其自己的父对象)
对于数字字段(Integer, Float),值应为相应的类型
因为Boolean,值应为a 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)
id使用中的值 更新现有id的记录values。不能用于create()。
(2, id, _)
id从集合中删除id的记录,然后删除它(从数据库中)。不能用于create()。
(3, id, _)
id从集合中删除id的记录,但不删除它。不能用 One2many。不能用于 create()。
(4, id, _)
将id的现有记录添加id到集合中。不能用One2many。
(5, _, _)
从集合中删除所有记录,相当于3明确地在每条记录上使用该命令。不能用 One2many。不能用于 create()。
(6, _, ids)
替换由集合中的所有现有的记录ids列表,等同于使用该命令5,然后命令 4每个id中ids。
标记为_上面列表中的值将被忽略,并且可以是任何内容,通常0或False。

read([fields])
在self低级/ RPC方法中读取记录的请求字段。在Python代码中,首选browse()。

参数 fields - 要返回的字段名称列表(默认为所有字段)
返回 将字段名称映射到其值的字典列表,每个记录使用一个字典
加薪 AccessError - 如果用户对某些给定记录没有读取权限
read_group(domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
获取按给定groupby字段分组的列表视图中的记录列表

参数
domain - 列出指定搜索条件的列表[[‘field_name’,‘operator’,‘value’],…]
fields(list) - 在对象上指定的列表视图中存在的字段列表。每个元素都是’field’(字段名称,使用默认聚合)或’field:agg’(聚合字段聚合函数’agg’)或’name:agg(field)’(聚合字段带’agg’)并将其作为“名称”返回)。可能的聚合函数是PostgreSQL(https://www.postgresql.org/docs/current/static/functions-aggregate.html)和’count_distinct’提供的函数,具有预期的含义。
groupby(list) - 将记录分组的groupby描述列表。groupby描述是字段(然后它将按该字段分组)或字符串’field:groupby_function’。目前,支持的唯一功能是“日”,“周”,“月”,“季度”或“年”,它们只适用于日期/日期时间字段。
offset(int) - 要跳过的可选记录数
limit(int) - 可选的最大返回记录数
orderby(list) - 可选order by规范,用于覆盖组的自然排序顺序,另请参阅search() (仅支持当前的多个字段)
lazy(bool) - 如果为true,则结果仅按第一个groupby分组,其余的groupbys放在__context键中。如果为false,则所有groupbys都在一次调用中完成。
返回
字典列表(每个记录一个字典)包含:

按groupby参数中的字段分组的字段值
__domain:指定搜索条件的元组列表
__context:带参数的字典 groupby
返回类型 [{‘field_name_1’:值,…]
加薪 AccessError -
如果用户对请求的对象没有读取权限
如果用户试图绕过访问规则以读取请求的对象
搜索
search(args[, offset=0][, limit=None][, order=None][, count=False])
根据args 搜索域搜索记录。

参数
args - 搜索域。使用空列表匹配所有记录。
offset(int) - 要忽略的结果数(默认值:无)
limit(int) - 要返回的最大记录数(默认值:全部)
order(str) - 排序字符串
count(bool) - 如果为True,则只计算并返回匹配记录的数量(默认值:False)
返回 最多limit匹配搜索条件的记录
加薪 AccessError -
如果用户试图绕过访问规则以读取请求的对象。
search_count(args) → int
返回与提供的域匹配的当前模型中的记录数。

name_search(name=’’, args=None, operator=‘ilike’, limit=100) → records
搜索与给定name模式相比具有与给定模式匹配的显示名称的记录 operator,同时还匹配可选搜索域(args)。

这用于例如基于关系字段的部分值来提供建议。有时被视为反函数name_get(),但不能保证。

此方法相当于search()使用基于搜索结果的搜索域进行调用,display_name然后name_get()搜索结果。

参数
name(str) - 要匹配的名称模式
args(list) - 可选的搜索域(参见search()语法),指定进一步的限制
operator(str) - 用于匹配的域运算符name,例如 ‘like’或’=’。
limit(int) - 可选的最大返回记录数
返回类型 名单
返回 (id, text_repr)所有匹配记录的对列表。
记录集操作
ids
此记录集中的实际记录ID列表(忽略要创建的记录的占位符ID)

ensure_one()
验证当前的recorset是否包含单个记录。否则会引发异常。

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

if record.exists():
    ...

按照惯例,新记录将作为现有记录返回。

filtered(func)
在选择的记录self,从而func(rec)为真,并返回它们作为一个记录。

参数 func - 字段名称的函数或点分隔序列
sorted(key=None, reverse=False)
返回self订购的记录集key。

参数
key - 返回每个记录的比较键的一个参数的函数,或字段名称,或者None,在这种情况下,记录按默认模型的顺序排序
反向 - 如果True,以相反的顺序返回结果
mapped(func)
应用于func所有记录self,并将结果作为列表或记录集(如果func返回记录集)返回。在后一种情况下,返回的记录集的顺序是任意的。

参数 func - 一个函数或以点分隔的字段名称序列(字符串); 任何falsy值只返回记录集self
环境交换
sudo([user=SUPERUSER])
返回附加到提供的用户的此记录集的新版本。

默认情况下,它返回一个SUPERUSER记录集,其中绕过访问控制和记录规则。

使用sudo可能导致数据访问跨越记录规则的边界,可能混合要隔离的记录(例如,来自多公司环境中的不同公司的记录)。

这可能会导致在多种方法中选择一条记录的方法产生不直观的结果 - 例如获取默认公司或选择物料清单。

由于必须重新评估记录规则和访问控制,因此新记录集不会从当前环境的数据高速缓存中受益,因此以后的数据访问可能会在从数据库重新获取时产生额外的延迟。返回的记录集具有与之相同的预取对象self。

with_context([context][, **overrides]) → records
返回附加到扩展上下文的此记录集的新版本。

扩展上下文要么是合并提供的context, 要么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)
返回附加到提供的环境的此记录集的新版本

警告
新环境不会受益于当前环境的数据缓存,因此以后的数据访问可能会在从数据库重新获取时产生额外的延迟。返回的记录集具有与之相同的预取对象self。

字段和视图查询
fields_get([fields][, attributes])
返回每个字段的定义。

返回的值是字典的字典(由字段名称指示)。_inherits’d字段包括在内。字符串,帮助和选择(如果存在)属性已翻译。

参数
allfields - 要记录的字段列表,全部为空或未提供
attributes - 要为每个字段返回的描述属性列表,如果为空或未提供则全部
fields_view_get([view_id | view_type=‘form’])
获取所请求视图的详细组成,如字段,模型,视图体系结构

参数
view_id - 视图的id或None
view_type - 如果view_id为None(‘form’,‘tree’,…)则返回的视图的类型
toolbar - 如果包含上下文操作,则为true
子菜单 - 已弃用
返回 描述所请求视图组成的字典(包括继承的视图和扩展)
加薪
AttributeError -
如果继承的视图具有未知的位置,可以使用“之前”,“之后”,“内部”,“替换”以外的其他视图
如果在父视图中找到“position”以外的某些标记
无效的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
无论日志的访问域(create_date,write_uid,…)应生成(默认值:True)

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
对象的生命周期阶段,由states属性使用 fields

类型 Selection
parent_id
用于在树结构中对记录进行排序,并启用域中的child_of 和parent_of运算符

类型 Many2one
parent_path
用于存储树结构的索引时_parent_store 设置为True - 必须声明index=True为正确操作。

类型 Char

方法装饰器

该模块提供了用于管理两种不同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)
返回一个装饰器,它指定“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验证失败,应该提高。

警告
@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 "")

在显示该字段的表单视图中,将在修改其中一个给定字段时调用该方法。在包含表单中存在的值的伪记录上调用该方法。该记录上的字段分配会自动发送回客户端。

该方法可能会返回字典以更改字段域并弹出警告消息,就像在旧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。

参数
model - 模型名称,或’self’当前模型
downgrade - downgrade(self, value, *args, **kwargs) 将记录样式value转换为传统样式输出的函数
upgrade - upgrade(self, value, *args, kwargs) 将传统样式value转换为记录样式输出的函数
这些参数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)

请注意,修饰方法必须满足该约定。

这些装饰器是自动继承的:覆盖装饰的现有方法的方法将使用相同的方法进行修饰 @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)

请注意,包装器方法使用第一种方法的docstring。

odoo.api.v8(method_v8)
装饰一个仅支持新式api的方法。可以通过重新定义具有相同名称的方法并使用以下方法装饰来提供旧式api v7():

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

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

请注意,包装器方法使用第一种方法的docstring。

字段

基本领域

class odoo.fields.Field(string=, **kwargs)
字段描述符包含字段定义,并管理记录上相应字段的访问和分配。在实例化字段时可能会提供以下属性:

参数
string - 用户看到的字段的标签(字符串); 如果未设置,ORM将获取类中的字段名称(大写)。
help - 用户看到的字段的工具提示(字符串)
readonly - 字段是否为readonly(默认为boolean False)
required - 是否需要字段的值(默认为boolean False)
index - 字段是否在数据库中建立索引(默认为布尔值False)
default - 字段的默认值; 这可以是静态值,也可以是记录集并返回值的函数; 用于 default=None丢弃该字段的默认值
states - 将状态值映射到UI属性 - 值对列表的字典; 可能的属性是:‘readonly’,‘required’,‘invisible’。注意:任何基于状态的条件都要求state在客户端UI上提供字段值。这通常通过将其包括在相关视图中来完成,如果与最终用户不相关,则可能使其不可见。
groups - 以逗号分隔的组xml id列表(字符串); 这限制了仅对给定组的用户的字段访问
copy(bool) - 是否应在复制记录时复制字段值(默认值:True对于普通字段,Falsefor one2many和计算字段,包括属性字段和相关字段)
oldname(string) - 此字段的先前名称,以便ORM可以在迁移时自动重命名
计算字段
可以定义一个字段,其值是计算的,而不是简单地从数据库中读取。下面给出了特定于计算字段的属性。要定义此类字段,只需为该属性提供值即可compute。

参数
compute - 计算字段的方法的名称
inverse - 反转字段的方法的名称(可选)
search - 在字段上实现搜索的方法的名称(可选)
store - 字段是否存储在数据库中(默认情况下,False在计算字段上为boolean )
compute_sudo - 是否应将该字段重新计算为超级用户以绕过访问权限(默认情况下为boolean False)
对于给定的方法compute,inverse并search在模型的方法。它们的签名如下例所示:

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)]

compute方法必须在调用的记录集的所有记录上分配字段。odoo.api.depends()必须在compute方法上应用装饰器来指定字段依赖性; 这些依赖关系用于确定何时重新计算字段; 重新计算是自动的,并保证缓存/数据库的一致性。请注意,相同的方法可用于多个字段,您只需分配方法中的所有给定字段; 对于所有这些字段,将调用该方法一次。

默认情况下,计算字段不会存储到数据库中,而是即时计算。添加属性store=True会将字段的值存储在数据库中。存储字段的优点是在该字段上搜索由数据库本身完成。缺点是在必须重新计算字段时需要数据库更新。

正如其名称所示,反向方法执行计算方法的反转:调用的记录具有字段的值,您必须对字段依赖项应用必要的更改,以便计算给出预期值。请注意,默认情况下,只读取没有逆方法的计算字段。

在对模型进行实际搜索之前处理域时会调用搜索方法。它必须返回一个等同于条件的域:field operator value。

相关领域
通过遵循一系列关系字段并读取到达模型上的字段来给出相关字段的值。要遍历的完整字段序列由属性指定

参数 相关的 - 字段名称序列
一些字段属性是从源字段自动复制,如果他们不重新定义:string,help,readonly,required(仅当需要在序列中的所有字段), ,groups,digits,size, translate,sanitize,selection,comodel_name,。domain context从源字段复制所有无语义属性。

默认情况下,相关字段的值不会存储到数据库中。添加属性store=True以使其存储,就像计算字段一样。修改其依赖项后,将自动重新计算相关字段。

公司依赖的领域
以前称为“财产”字段,这些字段的价值取决于公司。换句话说,属于不同公司的用户可能在给定记录上看到该字段的不同值。

参数 company_dependent - 该字段是否依赖于公司(布尔值)
增量定义
字段在模型类上定义为类属性。如果扩展模型(请参阅参考资料Model),还可以通过在子类上重新定义具有相同名称和相同类型的字段来扩展字段定义。在这种情况下,字段的属性取自父类,并由子类中给出的属性覆盖。

例如,下面的第二个类只在字段上添加工具提示 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)
基地: odoo.fields._String

基本字符串字段,可以是长度限制的,通常在客户端中显示为单行字符串。

参数
size(int) - 为该字段存储的值的最大大小
trim(bool) - 指出值是否被修剪(默认情况下 True)。请注意,修剪操作仅由Web客户端应用。
translate - 启用字段值的转换; 用于 translate=True整体翻译字段值; translate 也可以是可调用,从而translate(callback, value) 转化value利用callback(term)来检索术语的翻译。
class odoo.fields.Boolean(string=, **kwargs)
基地: odoo.fields.Field

class odoo.fields.Integer(string=, **kwargs)
基地: odoo.fields.Field

class odoo.fields.Float(string=, digits=, **kwargs)
基地: odoo.fields.Field

精度数字由属性给出

参数 digits - 一对(total,decimal),或者一个获取数据库游标并返回一对的函数(total,decimal)
class odoo.fields.Text(string=, **kwargs)
基地: odoo.fields._String

非常相似,Char但用于较长的内容,没有大小,通常显示为多行文本框。

参数 translate - 启用字段值的转换; 用于 translate=True整体翻译字段值; translate 也可以是可调用,从而translate(callback, value) 转化value利用callback(term)来检索术语的翻译。
class odoo.fields.Selection(selection=, string=, **kwargs)
基地: odoo.fields.Field

参数
selection - 指定此字段的可能值。它被赋予,可以是对列表(value,string),或一模型的方法,或方法的名称。
selection_add - 在重写字段的情况下提供选择的扩展。它是对(value,string)的列表。
selection除相关字段或字段扩展名外,该属性是必需的 。

class odoo.fields.Html(string=, **kwargs)
基地: odoo.fields._String

日期和日期时间字段

日期和日期时间是任何类型的业务应用程序中非常重要的领域,它们在许多流行的Odoo应用程序中大量使用,例如物流或会计,它们的滥用可能会产生看不见但又痛苦的错误,此摘录旨在为Odoo开发人员提供所需的知识。避免滥用这些字段。

将值分配给日期/日期时间字段时,以下选项有效:
日期字段的正确服务器格式(YYYY-MM-DD)字符串,日期字段的 (YYYY-MM-DD HH:MM:SS)字符串。
一个date或一个datetime对象。
False或None。
如果不确定分配给Date / Datetime对象的值的类型,最好的操作方法是将值传递给 to_date()或to_datetime() 分别尝试将值转换为date或datetime对象,然后可以将其赋值到有关的领域。


要解析来自外部来源的日期/日期时间:

fields.Date.to_date(self._context.get('date_from'))

日期/日期时间比较最佳实践:
日期字段只能与日期对象进行比较。
日期时间字段只能与datetime对象进行比较。
警告
表示日期和日期时间的字符串可以在彼此之间进行比较,但结果可能不是预期的结果,因为日期时间字符串将始终大于日期字符串,因此非常 不鼓励这种做法。

具有日期和日期时间的常见操作(例如添加,减法或获取期间的开始/结束)通过Date和来公开 Datetime。这些助手也可以通过导入获得odoo.tools.date_utils。

class odoo.fields.Date(string=, **kwargs)
基地: odoo.fields.Field

static add(*args, **kwargs)
返回的总和value及relativedelta。

参数
值 - 初始日期或日期时间。
args - 直接传递给的位置args relativedelta。
kwargs - 直接传递给的关键字args relativedelta。
返回 生成的日期/日期时间。
static context_today(timestamp=None)
以适合日期字段的格式返回客户端时区中显示的当前日期。此方法可用于计算默认值。

参数
记录 - 从中获取时区的记录集。
timestamp(datetime) - 要使用的可选日期时间值而不是当前日期和时间(必须是日期时间,不能在时区之间转换常规日期)。
返回类型 日期
static end_of(granularity)
从日期或日期时间结束时间段。

参数
值 - 初始日期或日期时间。
granularity - 字符串中的句点类型,可以是年,季,月,周,日或小时。
返回 与指定时间段的开始对应的日期/日期时间对象。
static start_of(granularity)
从日期或日期时间开始。

参数
值 - 初始日期或日期时间。
粒度 - 字符串中的句点类型,可以是年,季,月,周,日或小时。
返回 与指定期间的开始相对应的日期/日期时间对象。
static subtract(*args, **kwargs)
收益之间的差异value和relativedelta。

参数
值 - 初始日期或日期时间。
args - 直接传递给的位置args relativedelta。
kwargs - 直接传递给的关键字args relativedelta。
返回 生成的日期/日期时间。
static to_date()
尝试转换value为date对象。

此函数可以作为输入使用不同类型的类型:
一个虚假的对象,在这种情况下将返回None。
表示日期或日期时间的字符串。
日期对象,在这种情况下,对象将按原样返回。
日期时间对象,在这种情况下,它将被转换为日期对象,并且所有特定于日期时间的信息都将丢失(HMS,TZ,…)。
参数 value - 要转换的值。
返回 代表的对象value。
返回类型 日期
static to_string()
将一个date或datetime对象转换为字符串。

参数 value - 要转换的值。
返回 表示value服务器日期格式的字符串,如果value是类型datetime,则小时,分钟,秒,tzinfo将被截断。
返回类型 海峡
static today()
以ORM预期的格式返回当天。此函数可用于计算默认值。

class odoo.fields.Datetime(string=, **kwargs)
基地: odoo.fields.Field

static add(*args, **kwargs)
返回的总和value及relativedelta。

参数
值 - 初始日期或日期时间。
args - 直接传递给的位置args relativedelta。
kwargs - 直接传递给的关键字args relativedelta。
返回 生成的日期/日期时间。
static context_timestamp(timestamp)
返回转换为客户端时区的给定时间戳。此方法不适合用作默认初始值设定项,因为datetime字段在客户端显示时自动转换。对于默认值,fields.Datetime.now() 应该使用。

参数
记录 - 从中获取时区的记录集。
timestamp(datetime) - 要转换为客户端时区的天真日期时间值(以UTC表示)。
返回类型 约会时间
返回 时间戳在上下文时区中转换为时区感知日期时间。
static end_of(granularity)
从日期或日期时间结束时间段。

参数
值 - 初始日期或日期时间。
granularity - 字符串中的句点类型,可以是年,季,月,周,日或小时。
返回 与指定时间段的开始对应的日期/日期时间对象。
static now()
以ORM预期的格式返回当前日期和时间。此函数可用于计算默认值。

static start_of(granularity)
从日期或日期时间开始。

参数
值 - 初始日期或日期时间。
粒度 - 字符串中的句点类型,可以是年,季,月,周,日或小时。
返回 与指定期间的开始相对应的日期/日期时间对象。
static subtract(*args, **kwargs)
收益之间的差异value和relativedelta。

参数
值 - 初始日期或日期时间。
args - 直接传递给的位置args relativedelta。
kwargs - 直接传递给的关键字args relativedelta。
返回 生成的日期/日期时间。
static to_datetime()
将ORM value转换为datetime值。

此函数可以作为输入使用不同类型的类型:
一个虚假的对象,在这种情况下将返回None。
表示日期或日期时间的字符串。
日期时间对象,在这种情况下,对象将按原样返回。
日期对象,在这种情况下,它将转换为日期时间对象。
参数 value - 要转换的值。
返回 代表的对象value。
返回类型 约会时间
static to_string()
将一个datetime或date对象转换为字符串。

参数 value - 要转换的值。
返回 表示value服务器日期时间格式的字符串,如果value是类型date,则时间部分为午夜(00:00:00)。
返回类型 海峡
static today()
返回当天,午夜(00:00:00)。

关系字段

class odoo.fields.Many2one(comodel_name=, string=, **kwargs)
基地: odoo.fields._Relational

这样一个字段的值是大小为0(无记录)或1(单个记录)的记录集。

参数
comodel_name - 目标模型的名称(字符串)
domain - 在客户端(域或字符串)上设置候选值的可选域
context - 处理该字段时在客户端使用的可选上下文(字典)
ondelete - 删除引用记录时该怎么办; 可能的值是:‘set null’,‘restrict’,‘cascade’
auto_join - 是否在搜索该字段时生成JOIN(默认情况下为boolean False)
委托 - 将其设置为True可以从当前模型访问目标模型的字段(对应于_inherits)
comodel_name除相关字段或字段扩展名外,该属性是必需的。

class odoo.fields.One2many(comodel_name=, inverse_name=, string=, **kwargs)
基地: odoo.fields._RelationalMulti

One2many场; 这样一个字段的值是所有记录的记录集,comodel_name使得该字段inverse_name等于当前记录。

参数
comodel_name - 目标模型的名称(字符串)
inverse_name - (字符串)中的反向Many2one字段的 名称comodel_name
domain - 在客户端(域或字符串)上设置候选值的可选域
context - 处理该字段时在客户端使用的可选上下文(字典)
auto_join - 是否在搜索该字段时生成JOIN(默认情况下为boolean False)
limit - 读取时使用的可选限制(整数)
属性comodel_name和inverse_name是除在相关领域或领域扩展的情况下,强制性的。

class odoo.fields.Many2many(comodel_name=, relation=, column1=, column2=, string=, **kwargs)
基地: odoo.fields._RelationalMulti

Many2many场; 这样一个字段的值是记录集。

参数 comodel_name - 目标模型的名称(字符串)
comodel_name除相关字段或字段扩展名外,该属性是必需的。

参数
relation - 在数据库中存储关系的表的可选名称(字符串)
column1 - 引用表中“这些”记录的列的可选名称relation(字符串)
column2 - 引用表中“那些”记录的列的可选名称relation(字符串)
属性relation,column1并且column2是可选的。如果没有给出,名称将自动从型号名称生成,提供 model_name并且comodel_name不同!

参数
domain - 在客户端(域或字符串)上设置候选值的可选域
context - 处理该字段时在客户端使用的可选上下文(字典)
limit - 读取时使用的可选限制(整数)
class odoo.fields.Reference(selection=, string=, **kwargs)
基地: odoo.fields.Selection

继承和延伸

Odoo提供了三种不同的机制来以模块化方式扩展模型:

从现有模型创建新模型,向副本添加新信息,但保留原始模块的原样
扩展其他模块中定义的模型,替换以前的版本
将一些模型的字段委托给它包含的记录
Alt

经典继承

当同时使用_inherit和 _name属性时,Odoo使用现有的(提供的via _inherit)作为基础创建一个新模型 。新模型从其基础获取所有字段,方法和元信息(默认值和al)。

class Inheritance0(models.Model):
    _name = 'inheritance.0'
    _description = 'Inheritance Zero'

    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'
    _description = 'Inheritance One'

    def call(self):
        return self.check("model 1")

并使用它们:

 a = env['inheritance.0'].create({'name': 'A'})
        b = env['inheritance.1'].create({'name': 'B'})
            a.call()
            b.call()

会产生:

"This is model 0 record A"
            "This is model 1 record B"

第二个模型继承自第一个模型的check方法及其 name字段,但重写了call方法,就像使用标准的 Python继承一样。

延期

在使用_inherit但遗漏时 _name,新模型取代现有模型,实质上将其扩展到原位。这对于向现有模型添加新字段或方法(在其他模块中创建)或自定义或重新配置它们(例如更改其默认排序顺序)非常有用:

_name = 'extension.0'
    _description = 'Extension zero'

    name = fields.Char(default="A")

class Extension1(models.Model):
    _inherit = 'extension.0'

    description = fields.Char(default="Extended")
record = env['extension.0'].create({})
        record.read()[0]

会产生:

 record = env['extension.0'].create({})
        record.read()[0]

除非已被禁用,否则它还会产生各种自动字段

代表团

第三种继承机制提供了更大的灵活性(可以在运行时更改)但功耗更低:使用_inherits 模型将当前模型中找不到的任何字段的查找委托给“子”模型。通过Reference在父模型上自动设置的字段执行委派 。主要区别在于含义。使用委托时,模型 有一个而不是一个,在组合中转换关系而不是继承:

class Screen(models.Model):
    _name = 'delegation.screen'
    _description = 'Screen'

    size = fields.Float(string='Screen Size in inches')

class Keyboard(models.Model):
    _name = 'delegation.keyboard'
    _description = 'Keyboard'

    layout = fields.Char(string='Layout')

class Laptop(models.Model):
    _name = 'delegation.laptop'
    _description = 'Laptop'

    _inherits = {
        'delegation.screen': 'screen_id',
        'delegation.keyboard': 'keyboard_id',
    }

    name = fields.Char(string='Name')
    maker = fields.Char(string='Maker')

    # a Laptop has a screen
    screen_id = fields.Many2one('delegation.screen', required=True, ondelete="cascade")
    # a Laptop has a keyboard
    keyboard_id = fields.Many2one('delegation.keyboard', required=True, ondelete="cascade")
 record = env['delegation.laptop'].create({
            'screen_id': env['delegation.screen'].create({'size': 13.0}).id,
            'keyboard_id': env['delegation.keyboard'].create({'layout': 'QWERTY'}).id,
        })
            record.size
            record.layout

将导致:

  13.0
  'QWERTY'

并且可以直接在委托字段上书写:

 record.write({'size': 14.0})

警告
使用委托继承时,方法不是继承的,只是字段

域是一个标准列表,每个标准是三元组(a list或a tuple)的(field_name, operator, value)位置:

field_name(str)
当前模型的字段名称,或通过Many2one使用点符号遍历的关系,例如’street’ 或’partner_id.country’
operator(str)
使用操作比较field_name用value。有效的运营商是:

=
等于
!=
不等于

大于

=
大于或等于
<
小于
<=
小于或等于
=?
未设置或等于(如果返回true value或者是None或 False,其他行为一样=)
=like
匹配field_name反对value格局。_模式中的下划线 代表(匹配)任何单个字符; 百分号%匹配任何零个或多个字符的字符串。
like
匹配field_name反对%value%格局。与匹配前相似 =like但包装value’%’
not like
与%value%模式不匹配
ilike
不区分大小写 like
not ilike
不区分大小写 not like
=ilike
不区分大小写 =like
in
等于任何项目value,value应该是项目列表
not in
是不平等的所有项目 value
child_of
是一个value记录的孩子(后代)。

考虑模型的语义(即遵循命名的关系字段 _parent_name)。

value
变量类型,必须与operator命名字段相当(通过)
可以使用前缀形式的逻辑运算符组合域标准:

‘&’
逻辑AND,默认操作将标准相互组合。Arity 2(使用接下来的2个标准或组合)。
‘|’
逻辑OR,arity 2。
‘!’
逻辑NOT,arity 1。

主要是否定标准的组合

个别标准通常具有否定形式(例如=- > !=,<- > >=),这比否定正面更简单。


要搜索名为ABC的合作伙伴,来自比利时或德国,其语言不是英语:

[('name','=','ABC'),
 ('language.code','!=','en_US'),
 '|',('country_id.code','=','be'),
     ('country_id.code','=','de')]

该域名解释为:

    (name is 'ABC')
AND (language is NOT english)
AND (country is Belgium OR Germany)

从旧API移植到新API

在新的API中应避免使用裸列表,而是使用记录集
仍旧在旧API中编写的方法应由ORM自动桥接,无需切换到旧API,只需将它们称为新的API方法即可。有关更多详细信息,请参阅自动桥接旧API方法。
search() 返回记录集,例如浏览其结果没有意义
fields.related并fields.function使用带有a related=或compute=参数的普通字段类型替换
depends()在compute=方法必须是完整的,它必须列出所有的领域,其计算方法采用子场。最好有太多的依赖项(将在不需要的情况下重新计算字段)比不够(将忘记重新计算字段然后值将不正确)
删除onchange计算字段上的所有方法。当其中一个依赖项发生更改时,计算字段会自动重新计算,并且用于onchange客户端自动生成
所述装饰model()和multi()用于桥接从旧的API调用的上下文时,用于内部或纯新的API(例如计算)它们是无用
删除_default,替换default= 相应字段的参数
如果字段string=是字段名称的标题版本:

name = fields.Char(string="Name")

它没用,应该删除

该multi=参数在新API字段上不执行任何操作,compute=在相关结果的所有相关字段上使用相同的 方法
提供compute=,inverse=并search=通过名称的方法(作为一个字符串),这使得它们可重写的(消除了对中间的“蹦床”功能的需要)
仔细检查所有字段和方法是否有不同的名称,碰撞时没有警告(因为Python在Odoo看到任何东西之前处理它)
正常的new-api导入是from odoo import fields, models。如果需要兼容性装饰器,请使用from odoo import api, fields, models
避免one()装饰,它可能不会做你期望的
除去明确的定义create_uid, create_date, write_uid和 write_date田地一样,现在创建为常规的“合法”的领域,并且可以读取和写入像任何其他领域外的开箱
当直接转换不可能(语义无法桥接)或“旧API”版本不可取并且可以针对新API进行改进时,可以使用完全不同的“旧API”和“新API”实现使用v7()和的 相同方法名称v8()。首先应该使用旧的API样式定义该方法并使用v7()它进行修饰,然后使用完全相同的名称重新定义该方法,但使用新的API样式并进行修饰v8()。来自旧API上下文的调用将被分派到第一个实现,并且来自新API上下文的调用将被分派到第二个实现。一个实现可以通过切换上下文来调用(并经常)调用另一个实现。

危险
使用这些装饰器使得方法极难覆盖并且难以理解和记录

使用_columns或 _all_columns应该替换 _fields,它提供对新式odoo.fields.Field实例(而不是旧式 odoo.osv.fields._column)实例的访问。

使用新API样式创建的非存储计算字段不可 用,_columns只能通过检查_fields

重新分配self方法可能是不必要的,可能会破坏翻译内省
Environment对象依赖于某些threadlocal状态,必须在使用它们之前设置它们。odoo.api.Environment.manage()在尝试在尚未设置的上下文中使用新API时,有必要使用 上下文管理器,例如新线程或Python交互式环境:

>>> from odoo import api, modules
>>> r = modules.registry.RegistryManager.get('test')
>>> cr = r.cursor()
>>> env = api.Environment(cr, 1, {})
Traceback (most recent call last):
  ...
AttributeError: environments
>>> with api.Environment.manage():
...     env = api.Environment(cr, 1, {})
...     print env['res.partner'].browse(1)
...
res.partner(1,)

自动桥接旧的API方法

初始化模型时,如果它们看起来像旧API样式中声明的模型,则会自动扫描和桥接所有方法。这种桥接使它们可以从新的API风格方法中透明地调用。

方法是匹配的“老-API风格”,如果他们的第二个位置参数(后self)被称为无论是cr或cursor。该系统还识别被称为第三位置参数uid或user与第四被调用id或ids。它还识别出存在任何被调用的参数context。

当调用从一个新的API上下文这样的方法,系统会自动填入从当前匹配的参数 Environment(用于cr, user和 context)或当前的记录(用于id 和ids)。

在极少数情况下,可以通过装饰旧式方法来定制桥接:

完全禁用它,通过装饰方法 noguess()将没有桥接,方法将从新旧API样式完全相同的方式调用
显式定义网桥,这主要是针对不正确匹配的方法(因为参数以意想不到的方式命名):

cr()
将自动将当前光标预先添加到显式提供的参数,位置
cr_uid()
将自动将当前光标和用户的id添加到明确提供的参数中
cr_uid_ids()
将自动将当前光标,用户的id和记录集的id添加到显式提供的参数
cr_uid_id()
将循环遍历当前记录集并为每个记录调用该方法一次,将当前游标,用户的id和记录的id添加到显式提供的参数。

危险
从新的API上下文调用时,此包装器的结果始终是一个列表

所有这些方法都有一个_context-souffixed版本(例如cr_uid_context()),它也通过关键字传递当前上下文。

使用v7()和v8()将被忽略的双重实现, 因为它们提供了自己的“桥接”

猜你喜欢

转载自blog.csdn.net/weixin_41317565/article/details/86612227