Introduction
Quand on explore le modèle de données d’Odoo, on rencontre souvent le besoin d’afficher une information provenant d’un autre enregistrement directement sur un formulaire — sans forcer l’utilisateur à ouvrir la fiche liée. Le champ Related est la solution déclarative d’Odoo qui permet d’exposer ces valeurs liées sans dupliquer les données.
Plutôt que d’écrire une méthode Python pour calculer et copier une valeur, un champ Related suit simplement une chaîne de relations et récupère la valeur finale. C’est un outil très pratique pour les développeurs et pour les consultants utilisant Odoo Studio qui veulent enrichir une vue sans coder.
Ce guide détaille ce que stocke un champ Related, son fonctionnement dans le framework Odoo, comment le créer via Studio ou en Python, et des situations concrètes où il simplifie les processus métiers.
Qu’est-ce que le champ Related dans Odoo
Dans l’ORM d’Odoo, un champ Related n’est pas une nouvelle catégorie de type comme Float ou Char : c’est plutôt un raccourci qui montre un champ d’un autre modèle en suivant une chaîne de champs relationnels. Le type du champ Related reprendra celui du champ terminal vers lequel il pointe.
Exemple simple : une commande client (sale.order) possède un champ partner_id (Many2one vers res.partner). Un champ Related défini comme related='partner_id.country_id' permet d’afficher le pays du client directement sur la commande, sans créer une copie distincte du pays.
Pour l’utilisateur, un champ Related se présente comme n’importe quel autre champ du formulaire : si le champ final est un Char, il apparaîtra comme un champ texte ; s’il s’agit d’un Many2one, il sera rendu en liste déroulante ; pour un Boolean, on verra une case à cocher. L’affichage hérite naturellement du type du champ référencé.
Par défaut, les champs Related sont en lecture seule et non stockés en base. Ils reflètent donc toujours la valeur courante du champ source, mais ne peuvent pas être utilisés directement dans un domaine SQL pour filtrer ou rechercher, sauf si on active store=True.
Dans Odoo Studio, on peut ajouter un champ Related depuis l’interface sans toucher au code : on choisit le chemin relationnel et Studio crée le champ avec la configuration adéquate. C’est une méthode rapide et accessible pour les consultants souhaitant enrichir des formulaires.
Comment fonctionne ce champ
Lors de la lecture, Odoo parcourt la chaîne de noms séparés par des points. Chaque maillon, sauf le dernier, doit être un champ relationnel (Many2one, One2many, ou Many2many). Le dernier élément peut être de n’importe quel type de champ.
Voici un exemple d’implémentation simple d’un champ Related dans un module Python :
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
partner_country_id = fields.Many2one(
related='partner_id.country_id',
string='Customer Country',
store=True,
)
Dans cet exemple, Odoo suit partner_id jusqu’au partenaire, puis lit country_id. Le champ défini sur sale.order devient un Many2one qui reflète le pays du client.
Champs Related stockés vs non stockés
C’est la distinction essentielle : par défaut, store=False, ce qui signifie que la valeur est calculée à la demande à la lecture et n’est pas persistée dans la table du modèle.
Avec store=True, Odoo écrit la valeur dans la base quand la source change. Cela permet de filtrer, regrouper et rechercher sur ce champ au niveau SQL, ce qui est indispensable pour les rapports et les vues en liste performantes.
L’inconvénient est l’usage d’espace disque et le coût des écritures déclenchées lors des modifications de la source. Odoo gère cela via son système de dépendances, mais quand on travaille sur des modèles volumineux, il faut garder l’impact performance à l’esprit.
Lecture seule vs modifiable
Par défaut, un champ Related est en lecture seule. Si vous passez readonly=False, il devient éditable et toute modification sera répercutée sur l’enregistrement source. Autrement dit, modifier un Related sur une commande peut en réalité modifier la fiche client liée.
N’activez la réécriture que si vous souhaitez explicitement ce comportement de propagation. C’est utile pour certains scénarios (ex. édition rapide), mais dangereux si les utilisateurs ne savent pas qu’ils modifient un enregistrement partagé.
Attributs clés du champ
Voici les paramètres principaux que vous configurez pour un champ Related :
- related : la chaîne de champs séparés par des points (ex. 'partner_id.country_id'). C’est l’attribut obligatoire.
- store : passez à True pour persister la valeur en base et permettre filtres et regroupements.
- readonly : mettez False pour autoriser l’édition, ce qui écrira dans le modèle source.
- string : le libellé affiché. Par défaut, il reprend celui du champ terminal.
- depends : rarement nécessaire, car Odoo infère les dépendances depuis la chaîne related. Utile seulement dans des cas limites.
Interaction avec l’ORM d’Odoo
Lire un champ Related renvoie la valeur du champ terminal sur l’enregistrement lié. Si un maillon de la chaîne est vide (par exemple partner_id non renseigné), le champ renverra False — un comportement standard de l’ORM.
Les Related stockés sont utilisables dans domaines, vues et rapports. Les Related non stockés s’affichent dans les formulaires et listes mais ne peuvent pas servir de critère de recherche côté base de données sauf si le serveur évalue la logique en Python.
Cas d’usage en entreprise
Exemples concrets d’utilisation en entreprise
CRM et ventes : numéro de téléphone sur la commande
Les commerciaux veulent souvent voir le téléphone du client directement sur la commande. Un champ Related like related='partner_id.phone' sur sale.order expose ce numéro dans le bon contexte, accélère les relances et évite d’ouvrir chaque fiche client. En Studio, un consultant peut l’ajouter en quelques clics.
Comptabilité : devise de la société sur les lignes de facture
Dans des environnements multi-sociétés, il peut être utile d’afficher la devise de la société sur les lignes de facture. Un Related tel que related='move_id.company_id.currency_id' remonte la devise en passant par deux Many2one. Les chaînes à plusieurs niveaux fonctionnent, mais il vaut mieux limiter la profondeur pour la maintenance et la performance. En stockant ce champ, on peut ensuite filtrer et analyser les factures par devise.
Inventaire : catégorie produit sur les mouvements
Les équipes logistiques apprécient de voir la catégorie produit sur les lignes de mouvement sans ouvrir chaque fiche produit. Un Related product_id.categ_id sur stock.move.line affiche la catégorie et, si stocké, permet de regrouper les flux en rapports d’inventaire selon la famille produit.
Production : référence interne sur les composants
Sur l’atelier, afficher la référence interne d’un composant directement sur la ligne du bon de travail évite les erreurs de sélection. Un Related vers product_id.default_code sur les lignes mrp.workorder place cette information à portée de main et améliore la précision opérationnelle.
Projets et feuilles de temps : service ou département de l’employé
Pour analyser les coûts par département, les chefs de projet veulent parfois voir le département de l’employé sur chaque entrée de feuille de temps. Un Related employee_id.department_id sur account.analytic.line montre ce champ directement et, une fois stocké, permet de filtrer et d’agréger les temps par département dans les rapports.
Créer ou personnaliser un champ Related
Trois méthodes pour ajouter un champ Related selon le contexte technique
Via Odoo Studio (sans code)
Odoo Studio permet de créer des champs Related via l’interface. Voici les étapes générales :
- Ouvrir Studio depuis le menu principal.
- Aller sur le formulaire cible.
- Cliquer sur Ajouter un champ et choisir Related.
- Sélectionner pas à pas le chemin relationnel proposé.
- Donner un libellé et choisir si le champ doit être stocké ou modifiable.
- Enregistrer et fermer Studio.
Studio génère automatiquement le champ (préfixé x_studio_) et l’insère dans la vue. C’est la façon la plus rapide pour enrichir un formulaire sans toucher à la base de code.
Par code dans un module Python
Pour les développeurs, la définition se fait dans la classe du modèle. C’est la méthode recommandée lorsque vous avez besoin de contrôle en versioning et de déploiement multi-environnements :
from odoo import fields, models
class StockMoveLine(models.Model):
_inherit = 'stock.move.line'
product_category_id = fields.Many2one(
related='product_id.categ_id',
string='Product Category',
store=True,
)
Après définition, il faut ajouter le champ à la vue XML pour l’afficher. Lors de l’installation ou de la mise à jour du module, Odoo crée automatiquement la colonne en base si nécessaire. C’est l’approche standard pour des personnalisations maintenables.
Via l’API XML-RPC
Pour des déploiements automatisés, on peut créer un champ Related par l’API XML-RPC en définissant l’attribut related dans ir.model.fields :
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_partner_country_id',
'field_description': 'Customer Country',
'model_id': sale_order_model_id,
'ttype': 'many2one',
'relation': 'res.country',
'related': 'partner_id.country_id',
'store': True,
'readonly': True,
'state': 'manual',
}]
)
Avec l’API, il faut préciser manuellement le ttype et la relation puisque l’API n’infère pas automatiquement le type depuis la chaîne related, contrairement à l’ORM Python. C’est une méthode utile pour des scripts de configuration à distance.
Bonnes pratiques
1. Stockez le champ si vous devez filtrer ou grouper
Si l’on veut pouvoir filtrer une liste ou grouper un rapport par ce champ, définissez store=True. Sinon, la base ne pourra pas effectuer le filtre et Odoo devrait évaluer chaque enregistrement en Python — ce qui ne scale pas. Pour un affichage pur en formulaire, un champ non stocké suffit.
2. Limitez la profondeur de la chaîne
Les chaînes courtes (deux niveaux) sont performantes et faciles à maintenir. Des chemins très profonds multiplient les points de fragilité. Si vous en avez besoin, envisagez plutôt un champ calculé avec une logique Python claire.
3. Mesurez l’effet de readonly=False
Rendre un Related modifiable n’écrit pas une copie locale : cela modifie l’enregistrement source. Si vous autorisez cela (ex. partner_id.phone éditable depuis une commande), la modification impactera toutes les entités liées au même partenaire. Validez ce comportement avec les métiers.
4. Utilisez-les pour l’affichage, pas pour dupliquer des données
Un champ Related sert à montrer des données existantes dans leur contexte, pas à créer une copie indépendante qui pourrait diverger. Si vous avez besoin d’une valeur autonome pouvant évoluer séparément, préférez un champ classique initialisé via onchange ou action automatisée.
5. Vérifiez les droits d’accès
Un Related lit des données d’un autre modèle : si l’utilisateur n’a pas les droits de lecture sur ce modèle, le champ restera vide sans avertissement. Anticipez cet effet en testant les profils utilisateurs et en adaptant les autorisations si nécessaire.
Pièges fréquents
Filtrer sur un Related non stocké
Erreur fréquente : ajouter un Related à une liste puis tenter d’en faire un filtre alors que store=False. Dans ce cas, le filtrage SQL n’est pas possible ; le domaine échouera ou renverra un résultat vide. Ajoutez store=True pour tout champ destiné à servir de critère de recherche ou de groupement.
Comportement d’écriture inattendu
Beaucoup d’utilisateurs sont surpris quand readonly=False fait que leurs modifications changent la fiche source. Ce cas est courant quand des champs Related sont créés via Studio par des personnes peu familières avec la mécanique. Confirmez toujours avec les parties prenantes avant d’ouvrir l’édition.
Chaîne avec maillon vide
Si un maillon est vide, le Related retourne False et le champ apparaît vide. Dans du code Python qui lit la valeur, il faut gérer ce cas pour éviter des TypeError. Cela passe facilement inaperçu en test si toutes les données sont complètes, mais se révèle en production lorsque certains champs restent optionnels.
Quand préférer un champ calculé
Les Related sont parfaits pour refléter un champ simple à travers une relation. Si vous devez appliquer une transformation, des conditions ou une logique métier, un champ computed avec une méthode Python est plus adapté et plus maintenable que d’essayer de contorsionner des Related.
Problèmes de performance avec de nombreux Related stockés
Chaque Related stocké implique des mises à jour quand la source change. Si vous multipliez ces champs sur de gros jeux d’enregistrements et que les sources évoluent souvent, vous pouvez générer une charge d’écriture importante. Sur de gros projets, profilez l’impact et privilégiez les champs non stockés sauf si la précision en temps réel est indispensable.
Conclusion
Le champ Related est un outil pratique pour afficher des informations contextuelles sans multiplier les copies de données. Il permet d’afficher des valeurs provenant d’enregistrements liés dans n’importe quelle vue et, si nécessaire, de les persister pour le reporting.
Savoir quand activer store=True, quand autoriser readonly=False et comment gérer les maillons vides évitera la majorité des problèmes courants. Que vous développiez en Python, configuriez en Studio ou automatisiez des déploiements, maîtriser le Related rend votre modèle Odoo plus ergonomique et robuste.
Si vous modélisez ou étendez Odoo, les champs Related doivent figurer dans votre boîte à outils, aux côtés des champs calculés, Many2one et des autres types de champs présentés dans cette série.
Chez Dasolo, nous accompagnons les entreprises dans l’implémentation, la personnalisation et l’optimisation d’Odoo sur les volets Vente, Opérations, Comptabilité et plus encore. Si vous avez besoin d’aide pour concevoir votre modèle de données, ajouter des champs adaptés à vos processus, ou étendre Odoo avec du code propre et maintenable, nous pouvons vous accompagner. Contactez-nous pour discuter de la manière dont nous pouvons soutenir votre projet Odoo.