Understanding @api.depends vs @api.onchange in Odoo 19
One of the most confusing topics for many Odoo developers — especially beginners — is the difference between @api.depends and @api.onchange.
At first glance, both seem to react when a field changes. But internally, they work very differently and are used for completely different purposes.
Understanding when to use each one is extremely important for writing clean, efficient, and bug-free Odoo modules.
What is @api.depends?
@api.depends is used with computed fields.
It tells Odoo:
“Recompute this field whenever these dependent fields change.”
The value is computed:
on the server side
automatically
and can optionally be stored in the database
Example of @api.depends
from odoo import models, fields, api
class Student(models.Model):
_name = 'student.student'
name = fields.Char()
mark1 = fields.Float()
mark2 = fields.Float()
total = fields.Float(
compute='_compute_total',
store=True
)
@api.depends('mark1', 'mark2')
def _compute_total(self):
for record in self:
record.total = record.mark1 + record.mark2
How It Works
Whenever:
mark1or
mark2
changes, Odoo automatically recalculates total.
If store=True is used:
the value is stored in the database
searchable
usable in filters and reports
If store=False:
the value is calculated dynamically every time
What is @api.onchange?
@api.onchange is completely different.
It is used to dynamically update the form view when a user changes a field in the UI.
It only works:
inside forms
during user interaction
before saving the record
Most importantly:
@api.onchange does NOT store values automatically in the database.
Example of @api.onchange
from odoo import models, fields, api
class Student(models.Model):
_name = 'student.student'
age = fields.Integer()
category = fields.Char()
@api.onchange('age')
def _onchange_age(self):
if self.age < 18:
self.category = 'Minor'
else:
self.category = 'Adult'
What Happens Here?
When the user changes the age field:
the form updates instantly
categorychanges immediatelyno save is required
This improves user experience by giving live feedback.
Key Difference Between Them
| Feature | @api.depends | @api.onchange |
|---|---|---|
| Purpose | Compute field values | Update UI dynamically |
| Runs On | Server | Client/Form UI |
| Works Without Form | Yes | No |
| Works in Imports/API | Yes | No |
| Stores Values | Yes (if store=True) | No |
| Triggered During Save | Yes | No |
| Searchable | Yes (stored fields) | No |
| Best Use Case | Business logic | User interface assistance |
Real-World Understanding
Use @api.depends When:
calculating totals
computing balances
generating statuses
creating business logic
handling automatic backend calculations
Examples:
invoice totals
stock quantities
salary calculations
contract balances
Use @api.onchange When:
showing warnings
auto-filling fields
updating domains
suggesting values
improving user experience
Examples:
autofill customer address
update payment terms
warning messages
dynamically filtering products
Important Mistake Developers Make
Many developers incorrectly use @api.onchange for business logic.
That is dangerous.
Why?
Because @api.onchange only runs in the form view.
It will NOT execute during:
XML-RPC/API calls
imports
automated scripts
cron jobs
backend operations
This means your logic may silently fail.
Bad Practice Example
@api.onchange('qty', 'price')
def _onchange_amount(self):
self.total = self.qty * self.price
This looks correct in the UI.
But during imports or automated creation:
totalmay remain empty
Correct Approach
total = fields.Float(
compute='_compute_total',
store=True
)
@api.depends('qty', 'price')
def _compute_total(self):
for rec in self:
rec.total = rec.qty * rec.price
This works everywhere consistently.
Can Both Be Used Together?
Yes — and many professional modules do exactly that.
A common pattern is:
@api.depends→ handles actual business computation@api.onchange→ improves user experience in forms
This gives both:
reliable backend logic
smooth frontend interaction
Performance Considerations
@api.depends can become expensive if:
too many dependencies exist
computed fields trigger chains of recomputations
large datasets are involved
Best practices:
keep dependencies minimal
avoid unnecessary recomputations
use
store=Truecarefully
Final Thoughts
Both @api.depends and @api.onchange are essential in Odoo development, but they solve completely different problems.
The golden rule is simple:
Use @api.depends for business logic.
Use @api.onchange for UI behavior.
Once developers clearly understand this distinction, their modules become:
more stable
easier to maintain
more scalable
and far less buggy.
Mastering these ORM decorators is one of the key steps toward becoming an advanced Odoo developer.

Comments
Post a Comment