Creating Models(创建模型)
模型字段定义为模型本身的属性:
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
Warning!
这意味着您无法定义具有相同名称的字段和方法,它们会发生冲突
默认情况下,字段的标签(用户可见名称)是字段名称的大写版本,可以使用 string 参数修改:
field2 = fields.Integer(string="an other field")
关于有关各种字段类型和参数,请参阅 Fields。
默认值被定义为字段上的参数,值为:
a_field = fields.Char(default="a value")
或者通过函数来计算默认值的,函数需要返回一个值:
def compute_default_value(self):
return self.get_value()
a_field = fields.Char(default=compute_default_value)
Computed fields(计算字段)
字段可以使用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’***属性。该属性值为一个方法,方法返回值为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)]
- 对计算字段赋值,通过***inverse***属性来设置计算字段的值。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 fields
计算字段的特例是相关(代理)字段,它提供当前记录中模型字段的值。它们是通过设置相关参数来定义的,就像它们可以存储的常规计算字段一样:
nickname = fields.Char(related='user_id.partner_id.name', store=True)
onchange: updating UI on the fly(动态更新UI)
当用户更改表单中的字段值时(但尚未保存表单),根据该值自动更新其他字段会很有用。例如:更改税额或添加新发票行时更新最终总计。
- 计算字段会自动检查并重新计算,不需要 onchange。
- 对于非计算字段,onchange() 装饰器用于更新字段值:
@api.onchange('field1', 'field2') # 当这些字段被更改,会调用方法
def check_change(self):
if self.field1 < self.field2:
self.field3 = True
这些修改完成时将更新结果返回到客户端程序并展现给用户。
- 客户端自动调用计算字段和new-API onchanges,而无需在视图中添加它们
- 如果不想某一字段触发onchange,可以通过向视图中添加 on_change="0" 来实现。
<field name="name" **on_change**="0"/>
当用户编辑字段时,即使有功能字段或显式onchange取决于该字段,也不会触发任何接口更新。
onchange方法对这些记录上的虚拟记录赋值工作没有写入数据库,只是用来知道要将哪个值返回客户端。
Warning!
one2many或many2many字段不可能通过onchange修改自身。这是webclient限制
Low-level SQL(简单SQL)
环境中的***cr***属性是当前数据库事务的游标,允许直接执行SQL。当使用ORM难以表达的查询(例如复杂连接),或者出于性能原因就可以直接执行SQL来实现。
self.env.cr.execute("some_sql", param1, param2, param3)
由于模型使用相同的游标,并且Environment包含各种缓存,因此在使用原生SQL更改数据库时,必须无效这些缓存,否则模型的进一步操作可能会有问题。就需要使用SQL语句中的CREATE、UPDATE or DELETE而不是SELECT(用于读取数据库记录)来清除缓存。
可以使用 BaseModel 对象的 invalidate_cache() 方法执行清除缓存。