Problem Statement: Poorly designed computed fields trigger unnecessary recomputations or infinite loops due to incorrect dependency declarations (@api.depends), leading to performance issues and unstable behavior
Step 1 Identify the problematic computed field
Typical symptoms:
- Form view never finishes loading
- CPU spikes when opening records
- Logs show repeated recomputation
- Server freezes after record creation/update
Enable logs:
--log-level=debug
Look for repeating:
Computing field x_field_name
Step 2 Identify common WRONG patterns (most bugs come from here)
WRONG: Computed field depends on itself
@api.depends('total_amount')
def _compute_total_amount(self):
for rec in self:
rec.total_amount = rec.price * rec.qty
This causes infinite recomputation
WRONG: Writing to other fields inside compute
@api.depends('price', 'qty')
def _compute_total(self):
for rec in self:
rec.total = rec.price * rec.qty
rec.subtotal = rec.total * 0.9 # BAD
WRONG: Using write() inside compute
@api.depends('line_ids.amount')
def _compute_amount(self):
for rec in self:
rec.write({'total': sum(rec.line_ids.mapped('amount'))})
Triggers recursive recompute + database writes
Step 3 Define correct dependencies ONLY
Correct dependency declaration
@api.depends('price', 'qty')
def _compute_total(self):
for rec in self:
rec.total = rec.price * rec.qty
Rules:
Depend only on source fields
Never depend on computed field itself
Avoid @api.depends('*')
Step 4 Never modify other fields inside compute
Correct approach: separate computed fields
total = fields.Float(compute='_compute_total', store=True)
subtotal = fields.Float(compute='_compute_subtotal', store=True)
@api.depends('price', 'qty')
def _compute_total(self):
for rec in self:
rec.total = rec.price * rec.qty
@api.depends('total')
def _compute_subtotal(self):
for rec in self:
rec.subtotal = rec.total * 0.9
- Clean
- Predictable
- No loops
Step 5 Use store=True ONLY when required
BAD
total = fields.Float(compute='_compute_total', store=True)
If:
- Field is rarely searched
- Used only in UI
GOOD
total = fields.Float(compute='_compute_total')
store=True increases recomputation cost
Use only when:
- Searching
- Grouping
- Reporting
Step 6 Avoid ORM writes in compute (use onchange instead)
WRONG (compute)
@api.depends('qty')
def _compute_price(self):
for rec in self:
rec.price = rec.qty * 10
RIGHT (onchange)
@api.onchange('qty')
def _onchange_qty(self):
self.price = self.qty * 10
UI-only logic
No recomputation loops
Step 7 Use @api.depends_context when needed
If compute depends on company, language, or user:
@api.depends_context('company')
@api.depends('amount')
def _compute_tax(self):
for rec in self:
rec.tax = rec.amount * rec.company_id.tax_rate
Prevents unnecessary recomputation.
Step 8 Fix One2many / Many2one loops
COMMON LOOP
@api.depends('line_ids.total')
def _compute_total(self):
for rec in self:
rec.total = sum(rec.line_ids.mapped('total'))
If line.total depends back on parent → loop.
SAFE VERSION
@api.depends('line_ids.price', 'line_ids.qty')
def _compute_total(self):
for rec in self:
rec.total = sum(
line.price * line.qty for line in rec.line_ids
)
Step 9 Use SQL constraints instead of compute when possible
BAD compute for validation
@api.depends('qty')
def _compute_check(self):
if self.qty < 0:
raise ValidationError("Invalid")
GOOD constraint
@api.constrains('qty')
def _check_qty(self):
for rec in self:
if rec.qty < 0:
raise ValidationError("Quantity cannot be negative")
Step 10 Final Safe Computed Field Template (Best Practice)
total = fields.Float(
compute='_compute_total',
store=True,
)
@api.depends('price', 'qty')
def _compute_total(self):
for rec in self:
rec.total = rec.price * rec.qty if rec.price and rec.qty else 0.0
- No writes
- No recursion
- Correct dependencies
- Safe for production
Conclusion
In Odoo, infinite recomputation issues are almost always caused by impure computed fields fields that write data, depend on themselves, or have poorly defined dependencies. The fix is simple but strict: keep compute methods pure, declare minimal dependencies, avoid ORM writes, and separate UI logic from stored logic. When computed fields are treated as read-only calculations instead of business logic containers, performance stabilizes, recomputation stops, and your Odoo development system becomes predictable and scalable.
Top comments (0)