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装饰器异同