Skip to content

OD215 many2many-table-too-long

A Many2many's relation table name is longer than PostgreSQL allows.

Category Severity Series Needs the index
Correctness Error all yes

What it reports

A stored Many2many whose table name is longer than 63 characters: the relation it gives, or when it gives none, the name Odoo makes of the two models' tables, sorted, joined by _ and ended with _rel. A table is the model's _table when its classes set one, else its name with dots made underscores. A relation is reported at the module's last definition that sets it, and a name Odoo makes at the field's first definition, when that is in the module.

Why it matters

PostgreSQL cuts an identifier longer than 63 characters, so Odoo checks every relation table name when it sets up the model and refuses a longer one. The error stops the registry from loading: the module cannot be installed, and a database that has it does not start. Long model names reach the limit quickly once Odoo joins two of them, so give the field a shorter relation, and column1 and column2 with it.

A field that is related or computed without store=True has no table and is not checked. A model whose _table is not a string literal, or that its classes set differently, is not checked, nor a relation that is unknown. An attribute takes its value 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/quality_inspection.py
class QualityInspectionChecklistTemplate(models.Model):
    _name = "quality.inspection.checklist.template"
    _description = "Inspection checklist template"

    name = fields.Char()


class QualityInspectionChecklist(models.Model):
    _name = "quality.inspection.checklist"
    _description = "Inspection checklist"

    template_ids = fields.Many2many("quality.inspection.checklist.template")

Odoo names the table quality_inspection_checklist_quality_inspection_checklist_template_rel, 70 characters.

models/quality_inspection.py
class QualityInspectionChecklist(models.Model):
    _name = "quality.inspection.checklist"
    _description = "Inspection checklist"

    template_ids = fields.Many2many(
        "quality.inspection.checklist.template",
        "quality_checklist_template_rel",
        "checklist_id",
        "template_id",
    )

Suppressing

template_ids = fields.Many2many("quality.inspection.checklist.template")  # odooscan: ignore[OD215]

See suppressing a finding.