How to Implement @api.onchange vs @api.depends  in Odoo?

✅ Core Difference

Feature
@api.onchange
@api.depends
Purpose Trigger logic when a field changes in UI Recalculate a computed field when dependencies change
Execution Context Client-side only (form view) Server-side (ORM, UI, batch, imports, API, etc.)
Field Storage Doesn’t affect stored fields unless manually written Used with @compute, which can be stored or not
Usage Scenario Interactive UI feedback (set values, warnings) Auto-updated computed fields

📌 Real Use Case: Product-Based Discount

Using @api.onchange

@api.onchange(‘product_id’)

def _onchange_product_id(self):

    if self.product_id and self.product_id.list_price > 1000:

        self.discount = 10

  • Triggered only when the product is changed in the form view.
  • Ideal for quick UI updates (e.g., applying a discount).
Using @api.depends with @compute

discount = fields.Float(compute=‘_compute_discount’, store=True)

 

@api.depends(‘product_id’)

def _compute_discount(self):

for line in self:

        line.discount = 10 if line.product_id.list_price > 1000 else 0

  • Automatically computed when the product_id changes.
  • Works on all levels: UI, server, API, scheduled jobs, import, etc.
⚙️ When to Use What?
Use Case
Use @api.onchange
Use @api.depends
Form view interaction (set fields, warnings) ✅ Yes ❌ No
Dynamic computed field (stored or not) ❌ No ✅ Yes
Runs during data import / cron / API ❌ No ✅ Yes
Temporary visual feedback ✅ Yes ❌ No
Server-side data consistency ❌ No ✅ Yes

⚠️ Important Notes

  • @api.onchange does not persist unless explicitly written via self.field = value.
  • @api.depends automatically recalculates and is part of the ORM lifecycle.
  • Avoid mixing both on the same logic unless there’s a specific reason.
✅ Summary Table
Decorator
Trigger Context
Works in Backend
Works in UI
Suitable For
Stores Field?
@api.onchange UI only ❌ No ✅ Yes Form feedback, quick set ❌ No (manual)
@api.depends ORM full stack ✅ Yes ✅ Yes Auto-calculating fields ✅ Yes/No