OD221 self-dependency-not-recursive¶
A computed field depends on itself through other records without recursive=True.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Warning | saas~14.4 and later | yes |
What it reports¶
A path given to @api.depends that leads back to the computed field itself on another record of
its model, such as child_ids.total_weight on the method that computes total_weight, when the
field does not set recursive=True. The fields checked are those whose compute names the
decorated method, that are not related and give no depends. A field is reported once per module,
at the first such path.
Why it matters¶
A field that depends on itself on other records, such as a total over a tree, must be recomputed
along the whole hierarchy when one record changes, which Odoo does for a field it knows to be
recursive. When it resolves the dependencies of the fields, Odoo finds the field among its own,
marks it recursive itself and emits a UserWarning that it should be declared with
recursive=True. Declare it, so that the code says what the registry does and the warning goes.
Before saas~14.4, Odoo marks the field recursive without a warning, and the rule does not run.
Odoo resolves no dependencies for an abstract model, so a mixin is not reported, and from a
transient model it does not follow a path into a regular model. The walk stops at a field the
index does not find, or one that is not relational. A depends parameter on the field replaces
the decorator's paths, so such a field is not checked, and a self-dependency in that parameter is
not reported. A field whose compute is not a literal method name is not checked either.
The rule does not run for a module when the module or one of its dependencies depends on a module
that is not indexed. A model is skipped when the class that introduces it, with _name or as a
class Odoo names, is in a module outside the dependencies, or when a class of it, or of a model it
inherits or delegates to, has a plain Python base class or an _inherit element that is not a
literal, a parent whose fields the scan cannot see. A module that Odoo always installs with base,
such as web, counts as in depends.
Example¶
class ParcelPallet(models.Model):
_name = "parcel.pallet"
_description = "Parcel pallet"
parent_id = fields.Many2one("parcel.pallet")
child_ids = fields.One2many("parcel.pallet", "parent_id")
weight = fields.Float()
total_weight = fields.Float(compute="_compute_total_weight", store=True)
@api.depends("weight", "child_ids.total_weight")
def _compute_total_weight(self):
for pallet in self:
pallet.total_weight = pallet.weight + sum(pallet.child_ids.mapped("total_weight"))
class ParcelPallet(models.Model):
_name = "parcel.pallet"
_description = "Parcel pallet"
parent_id = fields.Many2one("parcel.pallet")
child_ids = fields.One2many("parcel.pallet", "parent_id")
weight = fields.Float()
total_weight = fields.Float(compute="_compute_total_weight", store=True, recursive=True)
@api.depends("weight", "child_ids.total_weight")
def _compute_total_weight(self):
for pallet in self:
pallet.total_weight = pallet.weight + sum(pallet.child_ids.mapped("total_weight"))