Skip to content

OD217 parent-store-without-path

A model sets _parent_store without an indexed parent_path field.

Category Severity Series Needs the index
Correctness Error all yes

What it reports

A class that sets _parent_store = True on a model with no parent_path field, or whose parent_path field is not indexed: it gives no index, or index=False. Any other literal index, such as "btree", counts as an index. A model is reported once per module, at the first of its classes that sets _parent_store.

Why it matters

With _parent_store, Odoo keeps the path of each record's ancestors in the parent_path column and answers child_of and parent_of searches with a prefix match on it. When it creates or updates the model's table, it adds the column if needed and logs an error when the model has no parent_path field, or when the field has no index. Without the field, the ORM cannot read or search the paths it stores; without the index, each hierarchy search scans the whole table. Before saas~11.3, Odoo keeps the hierarchy in parent_left and parent_right instead, and the rule stays silent on such a series. A module of unknown series is checked all the same, except a model that holds a parent_left field, taken as a sign of such a series. So a leftover parent_left on a later series hides a true finding, and a model on an earlier series without the field gets a false one: pass --odoo-version to settle both.

A model without a table of its own is left alone: an abstract model, or one with a class that sets _auto = False. So is a model with a class that sets _parent_store to anything but True, or an index that is not a literal. The field takes its index from the last definitions that set it, and is unknown when those disagree, as two definitions in different files of one module may: files load in the order of the imports, which is not indexed.

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

models/parcel_zone.py
class ParcelZone(models.Model):
    _name = "parcel.zone"
    _description = "Parcel zone"
    _parent_store = True

    name = fields.Char()
    parent_id = fields.Many2one("parcel.zone", ondelete="cascade")
models/parcel_zone.py
class ParcelZone(models.Model):
    _name = "parcel.zone"
    _description = "Parcel zone"
    _parent_store = True

    name = fields.Char()
    parent_id = fields.Many2one("parcel.zone", ondelete="cascade")
    parent_path = fields.Char(index=True)

Suppressing

_parent_store = True  # odooscan: ignore[OD217]

See suppressing a finding.