Passer au contenu principal

Champs relationnels Odoo cassés après la mise à niveau - Guide de réparation

Champs Many2one ou One2many cassés après la mise à niveau d'Odoo 17/18/19 ? Diagnostiquez les dérives de schéma, les changements de nom de comodèle et les changements de type de champ aujourd'hui en production.

E
ECOSIRE Research and Development Team
|4 mai 20266 min de lecture1.2k Mots|

Cet article est actuellement disponible en anglais uniquement. Traduction à venir.

After upgrading Odoo, certain forms render with empty fields where data clearly used to exist. The log shows:

After upgrading Odoo, certain forms render with empty fields where data clearly used to exist. The log shows:

WARNING: Many2one field 'sale.order.partner_invoice_id' references unknown comodel 'res.partner.invoice'

Or:

ERROR: relation "stock_picking_carrier_rel" does not exist

Or simply: data that used to be linked is now sitting in null fields. This is post-upgrade relational drift on Odoo 17.0/18.0/19.0 — usually triggered by comodel renames, field type changes, or missing OpenUpgrade scripts.

Quick Fix

For a missing Many2many join table (the second variant above), recreate it from a pre-upgrade backup:

-- Restore the join table data from a snapshot of the pre-upgrade database
-- (assuming you restored to a parallel DB called <db>_premigration)
INSERT INTO stock_picking_carrier_rel (picking_id, carrier_id)
SELECT picking_id, carrier_id
FROM   dblink('dbname=<db>_premigration',
              'SELECT picking_id, carrier_id FROM stock_picking_carrier_rel')
       AS t(picking_id integer, carrier_id integer)
ON CONFLICT DO NOTHING;

For a comodel rename (the first variant), patch the model reference in your code or wait for/install the OpenUpgrade script that handles the rename.

Why This Happens

Odoo's relational fields rely on three pieces of metadata: the comodel name, the column or join table, and the inverse relationship. Major version upgrades occasionally:

  1. Rename a comodel. account.tax.template was removed; account.tax is the only model now. Custom modules referencing the old name break.
  2. Change Many2one to One2many or vice versa. Rare but happens — mail.followers.partner_id shape changes have bitten upgrades.
  3. Drop a Many2many join table because the field was reorganized. The _rel table either gets renamed or replaced with a new one2many model.
  4. Change ondelete semantics, leaving cascade orphans where there used to be NULLs.
  5. Drop columns from inheritance — a parent field that was inherited and overridden by a child class can lose its column when the inheritance graph changes.

OpenUpgrade scripts handle most of these for official Odoo modules. Custom modules that reference renamed comodels need their own migration.

Step-by-Step Diagnosis

1. Find the broken field. The log usually names it. If not, walk the chatter:

SELECT model, name, ttype, relation
FROM   ir_model_fields
WHERE  ttype IN ('many2one', 'one2many', 'many2many')
  AND  relation NOT IN (SELECT model FROM ir_model);

This finds every field whose comodel does not exist. Each row is a broken field.

2. Compare to source. For each row, check whether the field exists in the source code:

grep -r "partner_invoice_id" /opt/odoo/addons/sale/models/

If the field is in source with a different comodel, you have a comodel rename. If it is missing entirely, the field was removed and your custom code or DB still references it.

3. Check Many2many join tables.

SELECT table_name
FROM   information_schema.tables
WHERE  table_name LIKE '%_rel'
  AND  table_schema = 'public';

Cross-reference against ir_model_fields rows of type many2many. Any field whose relation_table does not appear in this list is broken.

4. Check FK constraints.

SELECT conname, conrelid::regclass, confrelid::regclass
FROM   pg_constraint
WHERE  contype = 'f' AND NOT convalidated;

Invalidated FKs after upgrade indicate data the upgrade could not link.

5. Check OpenUpgrade analysis log. OpenUpgrade emits an openupgrade-analysis.txt listing every field rename, model rename, and removal. The fields you are seeing broken are usually in there — the question is whether your migration script applied the suggested fix.

Permanent Fix

For comodel renames in your custom code, update field declarations:

# Old (Odoo 17.0)
tax_id = fields.Many2one('account.tax.template')

# New (Odoo 18.0+)
tax_id = fields.Many2one('account.tax')

Then ship a migration script that renames the column data if the underlying data model changed:

# migrations/18.0.1.0.0/pre-migration.py
def migrate(cr, version):
    cr.execute("""
        UPDATE ir_model_fields
        SET    relation = 'account.tax'
        WHERE  relation = 'account.tax.template'
    """)

For missing join tables, recreate them from the pre-upgrade snapshot:

CREATE TABLE stock_picking_carrier_rel (
    picking_id integer NOT NULL REFERENCES stock_picking(id) ON DELETE CASCADE,
    carrier_id integer NOT NULL REFERENCES delivery_carrier(id) ON DELETE CASCADE,
    PRIMARY KEY (picking_id, carrier_id)
);
INSERT INTO stock_picking_carrier_rel
SELECT picking_id, carrier_id FROM <restored_premigration_table>;

Always verify counts before and after — a missing row is silent until reports notice the drop.

For Many2one to One2many shape changes, this is a serious migration. Read the OpenUpgrade analysis carefully, write the data transformation, and test on staging until counts match production exactly. ECOSIRE's Odoo migration team handles this kind of cross-shape migration on most major upgrades.

For dropped inherited columns, restore the column manually from backup if the data is critical, or accept the loss if it was unused. Always backup first.

How to Prevent It

  • Use OpenUpgrade. It exists for exactly this. Skipping it means writing migration scripts you do not need to write.
  • Restore production into staging before every major upgrade. Run the upgrade end-to-end. Compare row counts of every business table before and after. Any drop is investigated before production runs.
  • Inventory your custom modules. List every Many2one and Many2many. Map each to the source's current state. Rewrite or write migrations for anything renamed or moved.
  • Lock OCA dependencies to the version branch. A repo cloned from main on the day of the upgrade is a roll of the dice. Pin to the release tag or version branch.
  • Constraint snapshot. pg_dump --schema-only before the upgrade. Diff against pg_dump --schema-only after. Every dropped constraint is investigated.
  • Use db.backup automation. Production should have automatic point-in-time backups so you can compare data shape across the upgrade boundary easily, not just restore.

Frequently Asked Questions

Should I run the upgrade on a copy of production or in place?

Always on a copy first. The first run is your dry run — read the log carefully, fix every warning. The second run on production should be uneventful. Skipping the dry run is the most common cause of "broken relational fields" surfacing at the worst possible moment.

Can OpenUpgrade fix my custom modules?

OpenUpgrade ships scripts for every official Odoo and OCA module. For your custom modules, you write the migration scripts yourself, but you can use OpenUpgrade's helpers (openupgrade.rename_columns, openupgrade.rename_models) inside your scripts. They are correct, tested, and handle the FK reshuffling for you.

Why does Odoo not warn me about renamed comodels at install time?

It would, if the manifest version reflected the change. The warning happens during --update if the upgrade scripts ran. If you skip the upgrade scripts (because the manifest version was not bumped, or you ran -i instead of -u), Odoo silently keeps the old metadata. Always -u on existing databases.

My data looks correct in PostgreSQL but blank in the UI. What's happening?

Almost certainly a related field whose chain is broken — the data is there but the related lookup hits a NULL somewhere on the path. Use the SQL probe in step 1 of the diagnosis to find broken fields, fix the chain (or convert to a stored compute), and the UI lights up again.


Need help with a tricky Odoo error? ECOSIRE's Odoo experts have shipped 215+ modules — get expert help.

E

Rédigé par

ECOSIRE Team

Technical Writing

The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.

ECOSIRE

Transformez votre entreprise avec Odoo ERP

Implémentation, personnalisation et assistance expertes d'Odoo pour rationaliser vos opérations.