Introduction
Lorsque l'on commence le développement sur Odoo, un concept revient tout le temps : l'héritage. L'ORM d'Odoo permet aux modèles de se prolonger et de partager des attributs sans réécrire les mêmes définitions à chaque fois, ce qui évite la duplication et facilite la maintenance du code.
Les champs hérités incarnent ce principe : ils offrent à un modèle la possibilité d’exposer et d’utiliser des champs qui sont physiquement définis et stockés ailleurs. Une fois ce mécanisme intégré, la logique des relations entre objets Odoo devient beaucoup plus lisible.
Ce guide présente ce que sont les champs hérités, les trois méthodes d’héritage qui les génèrent, leur comportement en base de données, et comment les exploiter concrètement lors de vos personnalisations Odoo.
Qu'est-ce qu'un champ hérité dans Odoo ?
Dans l'ORM Odoo, un champ est dit hérité quand un modèle obtient accès à des champs définis sur un autre modèle via l'une des trois formes d’héritage. Plutôt que de redéfinir ces champs, le modèle enfant les réutilise tels quels.
C’est aussi pour cela que le modèle de données Odoo reste cohérent : le champ name d’un contact est toujours le même lorsqu’on l’affiche sur une facture, un devis ou une opportunité — tous lisent la même source de données.
Les trois types d’héritage dans Odoo
Odoo propose trois modes d’héritage distincts, chacun impliquant des règles différentes pour la gestion des champs et du stockage.
1. Héritage classique
C’est le schéma le plus fréquent. En indiquant seulement _inherit sans créer un nouveau _name, vous prolongez directement un modèle existant : vous lui ajoutez champs et méthodes. Aucun nouveau tableau SQL n’apparaît : les nouveaux champs s’ajoutent à la table initiale.
C’est la méthode utilisée par la plupart des modules pour étendre les modèles standards : par exemple des modules métier qui ajoutent des colonnes à res.partner. Les données restent dans la table partenaire, côte à côte avec les champs natifs.
2. Héritage de prototype
Lorsque vous combinez _inherit et _name, vous créez un nouveau modèle qui copie la structure du parent mais possède sa propre table en base. Les champs du parent sont dupliqués dans le modèle enfant ; les modifications du fils n’impactent pas le parent.
Ce pattern est moins fréquent pour de simples personnalisations, mais utile quand vous voulez un nouveau type d’enregistrement qui réutilise la structure d’un modèle existant sans partager la même table.
3. Héritage par délégation
L’héritage par délégation, déclaré via _inherits, est plus particulier : le modèle enfant contient un Many2one vers le parent et expose directement tous les champs du parent comme si c’étaient les siens. Les valeurs sont physiquement stockées dans la table du parent, pas dans celle du fils.
C’est souvent ce que les développeurs désignent quand ils parlent de « champs hérités » au sens strict : il n’y a pas duplication, le modèle fils lit et écrit les valeurs via la relation vers le parent.
Un exemple standard d’Odoo est la relation entre res.users et res.partner : tout utilisateur est aussi un contact. Le nom, l’e-mail et le téléphone sont gardés dans le partenaire et accessibles depuis l’utilisateur grâce à la délégation.
Comment fonctionne un champ hérité
Délégation : comment ça marche en coulisses
Avec _inherits, l'ORM crée un pont transparent entre deux tables. Lorsqu’on lit un champ hérité sur le fils, Odoo suit automatiquement le lien Many2one vers le parent et renvoie la valeur stockée là-bas.
Inversement, lorsqu’on écrit sur ce champ depuis le modèle enfant, Odoo met à jour directement l’enregistrement parent. Pour le développeur, le champ semble natif ; pour la base, les données résident sur la table parent.
La conséquence immédiate est l’absence de duplication : une modification du nom sur le partenaire se répercute partout où ce partenaire est référencé, y compris sur les enregistrements qui héritent de ses champs.
Héritage classique et base de données
Avec l’héritage classique, les nouveaux champs sont ajoutés à la table originelle du modèle. Il n’existe pas de seconde table : dans la base, le modèle étendu et le modèle d’origine sont la même entité. C’est la manière la plus simple et la plus courante d’étendre Odoo.
Les champs liés comme une forme légère d’héritage
Un champ related est un champ calculé qui lit une valeur depuis un enregistrement lié via une chaîne relationnelle. Ce n’est pas strictement de l’héritage de modèle, mais c’est souvent utilisé pour exposer des données de type « héritées » sans toucher à la structure du modèle cible.
Par exemple, on peut définir sur une commande un champ partner_country_id qui pointe sur partner_id.country_id. Le champ se comporte comme natif sur la commande, mais la source reste le partenaire.
Les champs liés peuvent être persistés en base avec store=True, ce qui accélère les recherches et tris au prix d’un coût de stockage et d’un besoin de recomputation quand la source change.
Résolution des champs au runtime
Au chargement d’une définition de modèle, Odoo calcule la carte complète des champs, y compris ceux hérités. Avant que le modèle soit utilisé, Odoo a déjà résolu l’origine de chaque champ — qu’il provienne de la propre table, d’une table parent via délégation ou d’une chaîne liée. Cette résolution a lieu au démarrage du serveur et est mise en cache pour les performances.
Cas d'usage métier
Les champs hérités ne sont pas une simple astuce technique : ils répondent à des besoins métiers concrets en garantissant la cohérence des données sans les dupliquer.
1. CRM et ventes : informations de contact
Dans le CRM, lorsqu’un commercial crée une opportunité, le nom, le téléphone et l’e-mail proviennent du partenaire lié. Si le contact évolue, tous les éléments liés — opportunités, devis, commandes — affichent immédiatement la nouvelle information, sans synchronisation manuelle.
Cette cohérence résulte de l’association de l’héritage classique et des champs liés : les modules CRM étendent res.partner et les vues commerciales affichent les infos du partenaire via des champs liés.
2. Produits et variantes
La gestion des variantes produit repose sur la délégation : product.product (la variante) délègue à product.template. Les attributs communs (nom, description, prix de vente) restent sur le template, tandis que les propriétés propres à la variante (code-barres, référence interne) se trouvent sur la variante elle-même.
Ainsi, vous pouvez gérer des dizaines de variantes pour un même article sans répéter le nom et la description à chaque enregistrement, ce qui économise de l’espace et simplifie les mises à jour.
3. Utilisateurs et contacts
Chaque utilisateur Odoo est lié à un contact : res.users hérite de res.partner via délégation. Mettre à jour l’e-mail d’un collaborateur met à jour à la fois le compte utilisateur et la fiche contact, car ils lisent la même source.
4. Inventaire : mouvements et infos produit
Les lignes de mouvement affichent les descriptions produit obtenues depuis le template via des champs liés. Les gestionnaires voient des informations produits à jour directement sur leurs listes de préparation sans duplication par le module inventaire.
5. Comptabilité : lignes de facture
Les lignes comptables renvoient aux produits et aux partenaires : le nom du produit, les comptes et la configuration fiscale affichés sur une facture proviennent des mêmes modèles produits/partenaires via les liens relationnels, assurant une présentation cohérente entre ventes et compta.
Créer ou personnaliser des champs hérités
Utiliser Odoo Studio
Odoo Studio offre une interface no-code pour modifier modèles et vues. Quand vous ajoutez un champ depuis Studio, il réalise en coulisse une forme d’héritage classique : il étend la définition du modèle et crée la colonne en base sans écrire de code Python.
Studio permet aussi de créer des champs liés : en choisissant « Champ lié », vous pointez sur n’importe quel champ accessible via une chaîne relationnelle depuis le modèle courant (par exemple le pays ou le numéro de TVA du client sur la commande de vente).
Pour la plupart des responsables métier et consultants fonctionnels, Studio est l’outil adapté : il gère la création, la migration en base et le placement dans les vues automatiquement.
Personnalisation technique en Python
Pour les développeurs, les champs hérités se définissent en Python via la classe models.Model de l’ORM Odoo.
Héritage classique : ajouter un champ à un modèle existant
Exemple d’approche : vous définissez un _inherit sur le modèle cible et déclarez votre nouveau champ dans la classe Python du module.
Héritage par délégation : créer un modèle qui réutilise des champs d’un existant
Avec _inherits, vous créez une liaison Many2one vers le parent et exposez ses champs sur votre nouveau modèle, tout en ajoutant vos propres champs spécifiques.
Champs liés : exposer une valeur depuis un enregistrement lié
Un champ défini avecrelated='chemin.relation'permet d’afficher une valeur provenant d’un enregistrement lié ;store=Truepermet de la persister en base si nécessaire pour les recherches.
Via l’API XML-RPC (configuration à distance)
Il est aussi possible de créer des champs via l’API XML-RPC en manipulant le modèle ir.model.fields. Cette méthode équivaut à ce que Studio fait et convient pour des déploiements automatisés sans accès direct au serveur.
Pour créer un champ lié via l’API, on crée un enregistrement ir.model.fields en définissant le type (par ex. many2one) et la chaîne related. C’est pratique pour l’installation de champs personnalisés dans des notebooks de configuration à distance.
Bonnes pratiques
Choisir le bon type d’héritage selon le besoin
Privilégiez l’héritage classique si vous voulez simplement ajouter des champs ou méthodes à un modèle existant : c’est la solution la plus simple et la plus répandue. Réservez la délégation aux cas où vous avez besoin de deux jeux d’enregistrements distincts reliés (par exemple une extension métier qui n’est pas, en soi, un contact).
Préférez les champs liés pour un accès en lecture
Si vous avez juste besoin d’afficher une valeur provenant d’un autre enregistrement dans une vue, un champ lié est plus léger et plus clair que de créer une relation par délégation. Il évite d’alourdir votre modèle avec des dépendances structurelles inutiles.
Attention au paramètre store=True sur les champs liés
Stocker un champ lié améliore les performances de recherche mais crée une copie en base : si la source change souvent, la recomputation peut devenir coûteuse et, dans des cas limites, provoquer des désynchronisations. Stockez uniquement quand vous avez un besoin réel de filtrer ou trier à grande échelle.
Préfixez toujours vos champs personnalisés par x_
Pour éviter les conflits avec des champs natifs ajoutés dans de futures versions d’Odoo, commencez vos champs personnalisés par x_ ou utilisez un namespace de module approprié.
Documentez votre chaîne d’héritage
Sur des personnalisations complexes, laissez un commentaire expliquant l’origine des champs et la logique derrière. Un champ x_country_code sur une commande n’éclairera pas forcément le prochain développeur : indiquer qu’il provient de partner_id.country_id.code évite les incompréhensions.
Gérez correctement les suppressions en cascade
Avec la délégation, le parent est souvent créé automatiquement lors de la création du fils. Pour éviter des orphelins lors de la suppression, définissez ondelete='cascade' sur le Many2one du _inherits, afin que la suppression du fils supprime aussi le parent quand c’est le comportement attendu.
Pièges fréquents
Confondre les trois types d’héritage
L’erreur classique des débutants est d’utiliser _inherit avec _name alors qu’ils voulaient faire une extension classique : cela crée un tout nouveau modèle au lieu d’étendre l’existant. Vérifiez toujours votre définition : si vous ne voulez pas créer un nouveau modèle, n’ajoutez pas _name.
Oublier de créer l’enregistrement parent avec _inherits
En délégation, le parent n’est pas toujours créé automatiquement selon la manière dont vous créez l’enregistrement (API, scripts). Si vous passez par des appels bas niveau, veillez à laisser l’ORM créer le parent ou créez-le vous-même et transmettez son ID, sinon vous rencontrerez des erreurs de contrainte en base.
Tenter de changer le type d’un champ via l’héritage
Odoo n’autorise pas la modification du type d’un champ existant via héritage. On peut ajuster des attributs (label, domaine, aide), mais transformer un champ Char en Integer, par exemple, provoquera une erreur à l’installation du module.
Abuser des champs liés stockés
Ajouter store=True à tous les champs liés pour gagner en performance est tentant, mais alourdit la base et complexifie la maintenance. Si la source varie fréquemment, la recomputation peut devenir problématique. Utilisez le stockage sélectivement selon un besoin concret de tri/filtrage sur de gros volumes.
Supposer que les droits du modèle enfant s’appliquent automatiquement
Les champs hérités via délégation résident sur le modèle parent : les règles d’accès du modèle enfant ne s’appliquent pas forcément au niveau de la base. Si vous limitez l’accès au modèle fils mais pas au parent, des utilisateurs pourraient lire les valeurs héritées en interrogeant directement le parent. Vérifiez toujours les règles de sécurité sur les deux modèles.
Conclusion
Les champs hérités ne sont pas une curiosité technique : ils structurent l’architecture d’Odoo. Les liens entre utilisateurs et contacts, entre variantes et templates, ou entre commandes et informations client reposent sur ces mécanismes pour garantir la cohérence et éviter la duplication.
Savoir quel type d’héritage choisir, quand préférer un champ lié et comment cela se matérialise en base de données rendra vos personnalisations Odoo beaucoup plus robustes. Vous gagnerez en clarté, en maintenabilité et en temps de débogage.
En résumé : l'ORM d'Odoo privilégie le fait qu'une donnée vive en un seul lieu et soit partagée depuis là. C’est le principe des champs hérités, et c’est ce qui préserve la cohérence du modèle de données au fur et à mesure que le système s’enrichit.
Besoin d'aide pour votre déploiement Odoo ?
Chez Dasolo, nous accompagnons des entreprises dans l’implémentation, la personnalisation et l’optimisation d’Odoo. Que vous bâtissiez un module sur-mesure, enrichissiez des modèles standards ou cherchiez à comprendre un comportement de données, notre équipe apporte une expérience pratique pour aller plus vite et éviter les erreurs coûteuses.
Si vous avez des questions sur votre modèle de données Odoo, votre stratégie de champs personnalisés ou votre implémentation technique, nous serons ravis d’échanger et d’analyser votre situation. Contactez-nous et trouvons ensemble la meilleure solution pour votre projet.