在Odoo 14中,@api.onchange()、@api.depends() 和 @api.constrains() 都是装饰器,用于定义特定类型的方法,以便实现不同的功能。这些装饰器分别用于字段值变化时的动作、计算字段值的逻辑以及在保存记录前执行的验证。以下是对它们的解释:
在Odoo 14中,@api.onchange() 装饰器用于定义一个方法,该方法会在特定字段的值发生变化时自动执行。这个装饰器通常用于创建动态计算或更新字段值的逻辑,而无需用户手动触发。以下是关于 @api.onchange() 装饰器的详细解释:
@api.onchange() 装饰的方法会在特定字段的值发生变化时自动触发执行。执行时机是在用户在表单中输入或修改字段值,并尝试离开该字段时(例如,通过按 Tab 键)。这使得您能够实时地根据用户输入或修改更新其他相关字段的值。
被 @api.onchange() 装饰的方法通常接收一个参数,通常命名为 vals 或 values,用于接收当前字段的新值。
通过检查该参数,您可以获取关于字段变化的信息,并根据需要采取相应的行动。
@api.onchange() 方法通常没有显式的返回值,因为它主要用于更新其他字段的值,而不是返回结果给用户。
但是,如果您想要通过界面向用户提供一些信息,可以返回一个包含键值对的字典,例如 {'warning': {'title': 'Warning', 'message': 'Your custom message'}}。
@api.onchange() 方法并不总是在所有情况下都能触发。例如,在通过编程方式更改字段的值时,可能不会触发 @api.onchange()。
此外,@api.onchange() 通常仅在编辑模式下才会触发,而在创建记录时不会。
以下是一个简单的例子,演示了如何使用 @api.onchange() 更新其他字段:
在这个例子中,当用户在 name 字段中输入或修改值时,_onchange_name 方法将自动执行,更新 description 字段的值。
pythonCopy code
from odoo import models, fields, api
class MyModel(models.Model):
_name = 'my.model'
name = fields.Char(string='Name')
description = fields.Text(string='Description')
@api.onchange('name')
def _onchange_name(self):
if self.name:
self.description = 'Description for ' + self.name
@api.onchange() 提供了一种方便的方式来实时响应用户输入或字段值的变化,并在界面上更新相关的数据。
在 Odoo 14 中,@api.depends() 装饰器用于定义计算字段,并指示这个计算字段依赖于其他字段。这样,当被依赖的字段值发生变化时,计算字段会被重新计算。以下是关于 @api.depends() 的详细解释:
@api.depends() 装饰的方法(计算字段的计算方法)会在以下情况下被触发:
当记录被创建时,计算字段的计算方法会被调用一次。
当计算字段依赖的字段的值发生变化时,计算字段的计算方法会被触发。
让我们通过一个示例来解释 @api.depends() 装饰器的使用。假设有一个模型 SaleOrder,其中包含 order_lines 字段表示销售订单中的订单行。我们希望计算订单的总金额,因此我们可以使用 @api.depends() 装饰器:
from odoo import models, fields, api
class SaleOrder(models.Model):
_name = 'sale.order'
name = fields.Char(string='Order Reference', required=True)
order_lines = fields.One2many('sale.order.line', 'order_id', string='Order Lines')
total_amount = fields.Float(string='Total Amount', compute='_compute_total_amount', store=True)
@api.depends('order_lines.price_subtotal')
def _compute_total_amount(self):
for order in self:
order.total_amount = sum(line.price_subtotal for line in order.order_lines)
在上述示例中,total_amount 字段是一个计算字段,其值依赖于 order_lines.price_subtotal。因此,每当 order_lines 中的任何订单行的 price_subtotal 发生变化时,_compute_total_amount 方法会被触发重新计算。
store=True 参数: 当 store=True 时,计算字段的值将被存储在数据库中,以提高检索性能。但请注意,存储计算字段可能会增加数据库存储和更新的开销,因此只在需要时使用。
不要在 @api.depends() 中进行写操作: 避免在 @api.depends() 方法中进行写操作,因为这可能导致无限循环。如果需要执行写操作,可以考虑使用 @api.onchange()。
避免长时间运行的计算: 由于计算字段的计算方法在数据库中执行,避免在计算方法中执行过于复杂或长时间运行的计算。
通过合理使用 @api.depends() 装饰器,您可以构建出灵活而高效的计算字段,以满足您的业务逻辑需求。
在 Odoo 14 中,@api.constrains() 装饰器用于定义约束,以确保模型记录符合特定的条件。以下是对 @api.constrains() 装饰器的详细解释:
@api.constrains('field1', 'field2', ...)
def _check_constraints(self):
for record in self:
# 执行约束检查
if record.field1 > record.field2:
raise ValidationError('field1 must be less than or equal to field2.')
@api.constrains() 装饰的方法会在记录执行 create()、write() 或 unlink() 操作时触发。它用于检查记录是否满足特定的约束条件。
@api.constrains() 装饰的方法接受一个参数,即 self,代表当前记录集。通过这个参数,您可以访问当前记录集中的字段值。
@api.constrains() 方法通常不需要返回值。如果约束检查失败,您可以引发 ValidationError 异常,以中止当前操作并返回错误消息。
被 @api.constrains() 装饰的方法通常用于检查记录的完整性,而不是执行写操作。避免在此方法中执行写操作,以防止无限循环
假设有一个 Product 模型,包含 quantity 和 min_quantity 字段,我们想确保 quantity 不小于 min_quantity。这个约束可以使用 @api.constrains() 装饰器:
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class Product(models.Model):
_name = 'product.product'
name = fields.Char(string='Product Name', required=True)
quantity = fields.Integer(string='Quantity', default=1)
min_quantity = fields.Integer(string='Minimum Quantity', default=0)
@api.constrains('quantity')
def _check_quantity(self):
for product in self:
if product.quantity < product.min_quantity:
raise ValidationError('Quantity cannot be less than Minimum Quantity.')
在这个例子中,_check_quantity 方法使用 @api.constrains() 装饰器,依赖于 quantity 字段。当执行 create() 或 write() 操作时,该方法会被触发,检查 quantity 是否小于 min_quantity,如果是,将引发 ValidationError 异常。
通过使用 @api.constrains() 装饰器,我们实现了一个简单的约束,以确保记录满足业务规则。