Sur un projet de migration Odoo, les erreurs qui remontent au chargement du module sont les plus faciles à traiter. Le serveur refuse de démarrer, la trace pointe une ligne, on corrige. Le vrai piège en Odoo 19, ce sont les dépréciations qui ne cassent rien au démarrage. Le module s'installe, les tests passent, la démo fonctionne, et le comportement dérive en production sans qu'aucun log ne le signale. name_get en est l'exemple le plus parlant.
name_get ne plante pas, il est simplement ignoré
Depuis Odoo 17, la méthode name_get() est dépréciée au profit du champ display_name1. En Odoo 19, l'ORM n'appelle plus name_get en interne pour construire le libellé d'un enregistrement. Le point important pour un mainteneur de module custom : si vous aviez surchargé name_get pour afficher, par exemple, [REF] Nom du client dans les listes déroulantes, cette surcharge existe toujours dans votre code, elle ne lève aucune erreur, et elle ne sert plus à rien. Odoo lit display_name, calculé ailleurs, et vos libellés reviennent au format par défaut.
Personne n'est prévenu. Le module se charge, l'utilisateur voit juste des intitulés qui ne correspondent plus à ce qui était demandé. C'est le genre de régression qu'un client remonte trois semaines après la mise en production, quand un commercial se plaint de ne plus retrouver ses références dans un champ many2one.
La correction consiste à surcharger _compute_display_name à la place2. Le champ display_name est un champ calculé standard, mis en cache pendant la transaction, que l'on peut redéfinir comme n'importe quel autre champ compute. On y ajoute ses dépendances avec @api.depends, et pour un libellé qui varie selon la langue ou un paramètre de session, @api.depends_context. Côté appels programmatiques, il faut remplacer les records.name_get() par une lecture directe de display_name, via records.mapped('display_name') ou records.read(['display_name']).
read_group : même logique, autre surface
Le second cas fréquent concerne les agrégations. La méthode read_group() est dépréciée en Odoo 19. Elle est scindée en deux3 : _read_group() pour l'usage backend, qui retourne des données brutes, et formatted_read_group() comme API publique renvoyant un format prêt à l'affichage. Cette séparation clarifie une méthode qui mélangeait depuis des années logique interne et présentation.
Le risque ici n'est pas tout à fait silencieux, puisque la signature change et que le code finit souvent par lever une erreur. Mais le piège est ailleurs. Beaucoup de rapports custom appellent read_group avec des arguments positionnels et parsent le résultat à la main. En passant à formatted_read_group, le format de sortie n'est pas identique, et un tableau de bord qui affichait des totaux corrects peut se mettre à afficher des chiffres décalés sans planter. Un agrégat qui renvoie une valeur plausible mais fausse est plus dangereux qu'une exception, parce que personne ne va le vérifier.
Les attributs privés qui disparaissent
Dernier lot, plus discret encore. Les guides de migration qui reprennent le changelog ORM d'Odoo 19 signalent la dépréciation des accès directs record._cr, record._context et record._uid, à remplacer par record.env.cr, record.env.context et record.env.uid4. Le namespace odoo.osv, hérité des versions très anciennes, est également déprécié.
Ces accès traînent dans beaucoup de bases de code anciennes, souvent copiés d'un module à l'autre sans être relus. Ils continuent de fonctionner un temps, puis cessent de le faire au fil des versions mineures, sans que la ligne fautive soit toujours évidente à retrouver.
Comment on les repère avant la prod
Un grep sur la base de code règle une bonne partie du problème. On cherche les définitions de def name_get, les appels à .name_get(, les read_group, et les ._cr, ._context, ._uid collés à une variable. C'est mécanique, mais c'est ce qui distingue une migration relue d'une migration qui compile.
| Ancien | Remplacement en Odoo 19 |
|---|---|
def name_get | def _compute_display_name |
records.name_get() | records.mapped('display_name') |
read_group() | _read_group() ou formatted_read_group() |
self._cr, self._context | self.env.cr, self.env.context |
Pour un panorama plus large des évolutions du moteur, nous avions détaillé les changements ORM qui touchent vos modules. Le présent billet se concentre sur un sous-ensemble précis : celui qui ne déclenche pas d'alerte.
Notre lecture
Une dépréciation qui plante est un cadeau, parce qu'elle vous force à agir tout de suite. Une dépréciation silencieuse reporte la facture sur le support, plusieurs semaines après le go-live, au moment le plus coûteux. En pratique, sur une migration vers Odoo 19, nous traitons ces trois familles en premier, avant même de lancer la suite de tests, parce que les tests ne les attrapent pas : un name_get surchargé qui n'est plus appelé ne casse aucune assertion, il change juste ce que l'utilisateur voit.
Le réflexe utile n'est pas de tout réécrire, mais de relire. Un balayage grep d'une demi-journée sur un module métier moyen suffit à sortir la liste des points à reprendre. Ce qui coûte cher, ce n'est pas la correction, c'est de la découvrir en production.
Sources
- Odoo, ORM Changelog 19.0 : https://www.odoo.com/documentation/19.0/developer/reference/backend/orm/changelog.html
- odoo/odoo, PR #122085 « Core: Remove name_get and use display_name instead » : https://github.com/odoo/odoo/pull/122085
- Cybrosys, Overview of Rare ORM Method name_get() in Odoo 19 : https://www.cybrosys.com/blog/overview-of-rare-orm-method-nameget-in-odoo-19
- Highshine, Odoo 19 Technical Developer Guide : https://highshine.in/odoo-19-technical-developer-guide
Footnotes
-
display_nameexiste sur tous les modèles depuis Odoo 8. La PR #122085 formalise le basculement dename_getvers ce champ comme représentation textuelle standard d'un enregistrement. ↩ -
_compute_display_nameest la méthode de calcul du champdisplay_name. On la surcharge pour personnaliser un libellé, en déclarant ses dépendances via@api.dependset, si nécessaire,@api.depends_context. ↩ -
_read_groupretourne des données non formatées destinées au code backend ;formatted_read_groupexpose une sortie mise en forme comme API publique. La référence de suivi côté Odoo est l'issue #163300. ↩ -
env.crest le curseur de base de données,env.contextle dictionnaire de contexte etenv.uidl'identifiant de l'utilisateur courant, tous accessibles via l'environnementenvd'un recordset. ↩