✅ Purpose & Concept
Feature |
@onchange | @compute (with @inverse) |
| Triggered When | Field changes in UI (form view only) | Any relevant field changes in DB (backend + UI) |
| Stores Value? | No (unless explicitly written) | Yes (if store=True) |
| Bidirectional? | One-way (UI to logic) | Yes (both compute and inverse) |
| Runs In | Client side | Server side (always) |
| Used In Views? | Yes | Yes |
📌 Real Use Case: Set Discount Based on Product
class SaleOrderLine(models.Model):
_inherit = ‘sale.order.line’
@api.onchange(‘product_id’)
def _onchange_product_id(self):
if self.product_id and self.product_id.list_price > 1000:
self.discount = 10
- When you choose a product, if its price exceeds 1000, a 10% discount will be automatically applied.
- Only works in form view during manual data entry.
- Does not trigger in batch creation or server-side operations like imports, APIs.
class SaleOrderLine(models.Model):
_inherit = ‘sale.order.line’
price_tax = fields.Float(compute=‘_compute_price_tax’, inverse=‘_inverse_price_tax’, store=True)
@api.depends(‘price_unit’, ‘tax_id’)
def _compute_price_tax(self):
for line in self:
tax = line.price_unit * 0.18 if line.tax_id else 0.0
line.price_tax = tax
def _inverse_price_tax(self):
for line in self:
if line.tax_id:
line.price_unit = line.price_tax / 0.18
- Automatically calculates tax from price and stores it.
- Also allows you to set the tax manually, and it will update price_unit accordingly using the inverse method.
- Useful for data consistency, import/export, and automations.
Situation |
Use @onchange |
Use @compute + @inverse |
| Field logic only needed in UI | ✅ Yes | ❌ Not necessary |
| Field must be updated on record change | ❌ No | ✅ Yes |
| Bi-directional calculation needed | ❌ No | ✅ Yes (compute + inverse) |
| Works during create/update/import | ❌ No | ✅ Yes |
| Temporary field logic (not stored) | ✅ Yes | ❌ Only if compute is not stored |
Decorator |
Direction |
Stores Data? |
Works in UI |
Works in Backend |
Bidirectional |
| @onchange | UI → Server | No | ✅ Yes | ❌ No | ❌ No |
| @compute only | Dependencies → Field | Yes/No | ✅ Yes | ✅ Yes | ❌ No |
| @compute + inverse | Field ↔ Logic | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |