1. @onchange 装饰器
@onchange 是一种基于 用户界面(UI)的触发器,用于监听某些字段的值在前端界面中发生变化时,自动调用对应的方法。
关键特点
- 触发时机: 当用户在界面上修改某个字段的值并切换到其他字段时,触发 @onchange 方法。
- 仅作用于前端: @onchange 的结果不会存储到数据库,仅在当前的会话中生效。
- 实时反馈: 用于动态更新界面中的其他字段,例如计算值、设置默认值或更新界面状态。
- 不可用于业务规则: 因为其结果不存储到数据库,因此不能依赖 @onchange 实现持久化业务逻辑。
示例代码
from odoo import models, fields, api
class SaleOrder(models.Model):
    _name = 'sale.order'
    product_id = fields.Many2one('product.product', string="Product")
    unit_price = fields.Float(string="Unit Price")
    quantity = fields.Integer(string="Quantity")
    total_price = fields.Float(string="Total Price", readonly=True)
    @api.onchange('product_id', 'quantity')
    def _onchange_calculate_price(self):
        if self.product_id and self.quantity:
            self.unit_price = self.product_id.list_price
            self.total_price = self.unit_price * self.quantity
        else:
            self.unit_price = 0.0
            self.total_price = 0.0

使用场景
- 根据用户选择的值动态更新其他字段的显示值。
- 动态调整字段的只读、必填或可见状态。
- 在界面上执行实时计算,如金额总计。
2. @depends 装饰器
@depends 是用于 后端计算字段 的触发器,用于声明一个字段的值依赖于其他字段的变更。
关键特点
- 触发时机: 当被声明依赖的字段值发生变化时,自动重新计算目标字段。
- 作用于后端: 其逻辑会影响数据库中的值,因为它通常与计算字段一起使用。
- 自动触发: 不需要用户交互,当依赖字段的值通过任何方式(UI 或后端代码)被修改时,都会触发重新计算。
- 适合复杂业务逻辑: 通常用于处理需要持久化的计算规则。
示例代码
from odoo import models, fields, api
class SaleOrder(models.Model):
    _name = 'sale.order'
    product_id = fields.Many2one('product.product', string="Product")
    unit_price = fields.Float(string="Unit Price", compute="_compute_price", store=True)
    quantity = fields.Integer(string="Quantity")
    total_price = fields.Float(string="Total Price", compute="_compute_price", store=True)
    @api.depends('product_id', 'quantity')
    def _compute_price(self):
        for record in self:
            if record.product_id and record.quantity:
                record.unit_price = record.product_id.list_price
                record.total_price = record.unit_price * record.quantity
            else:
                record.unit_price = 0.0
                record.total_price = 0.0


使用场景
- 自动计算字段的值,并将其存储到数据库中。
- 用于复杂的业务逻辑或规则需要被持久化的场景。
- 构建报表或筛选器时依赖的字段计算。
3. @onchange 和 @depends 的对比
| 特性 | @onchange | @depends | 
|---|---|---|
| 触发机制 | 用户在界面中修改字段值时触发 | 依赖字段的值发生变化时自动触发 | 
| 触发范围 | 仅限前端,结果不存储在数据库 | 作用于后端,计算结果可以存储到数据库 | 
| 结果是否持久化 | 不会持久化,仅在会话中有效 | 会持久化,计算结果存储到数据库中 | 
| 适用场景 | 实时更新界面、动态调整字段状态 | 后端字段计算、持久化业务逻辑 | 
| 常用装饰器组合 | 单独使用,与 @api.onchange 绑定 | 通常与 @api.depends 和 compute 字段搭配使用 | 
| 使用复杂性 | 适合简单的动态调整或实时显示 | 适合复杂的业务逻辑和持久化计算 | 
4. 总结
- @onchange: 是纯前端的,仅仅增强体验,但不能依赖,因为后端的入口会直接无视他。
- @depends: 前后端都支持,相对靠谱,但又不能完全替代onchange的,因为计算的是只读的,onchange是针对可写的预设值而已。
- 选择原则:- 如果结果仅用于界面显示或动态交互,选择 @onchange。
- 如果需要持久化计算结果并用于后续操作,选择 @depends。
 
5.扩展:可以将@onchange 和@depends 联合使用
在一些场景下,这两个可以结合使用,以实现更强大的逻辑处理能力。例如:
- @onchange 用于界面中的实时更新。
- @depends 用于后端的持久化计算。
示例代码
from odoo import models, fields, api
class SaleOrder(models.Model):
    _name = 'sale.order'
    product_id = fields.Many2one('product.product', string="Product")
    unit_price = fields.Float(string="Unit Price", compute="_compute_price", store=True)
    quantity = fields.Integer(string="Quantity")
    total_price = fields.Float(string="Total Price", compute="_compute_price", store=True)
    @api.depends('product_id', 'quantity')
    def _compute_price(self):
        for record in self:
            if record.product_id and record.quantity:
                record.unit_price = record.product_id.list_price
                record.total_price = record.unit_price * record.quantity
            else:
                record.unit_price = 0.0
                record.total_price = 0.0
    @api.onchange('product_id')
    def _onchange_product_id(self):
        if self.product_id:
            self.unit_price = self.product_id.list_price
        

第8章:odoo @onchange与@depends装饰器异同