Introduction
Les développeurs Odoo utilisent souvent Many2one pour relier deux enregistrements, et c’est la bonne solution dans la plupart des situations. Mais parfois le document lié peut appartenir à plusieurs modèles différents selon le contexte — commande de vente, facture, tâche de projet, etc. C’est précisément pour ces scénarios polyvalents que le champ Reference a été conçu.
Le champ Reference est l’un des types de champs les plus souples de l’ORM Odoo. Plutôt que de pointer toujours vers un seul modèle, il propose une liste de modèles possibles : l’utilisateur choisit d’abord le type de document, puis sélectionne l’enregistrement concret. Le lien obtenu est polymorphe et s’adapte aux flux métiers variés.
Ce guide explique ce que stocke un champ Reference, comment il se comporte dans les données Odoo, comment le créer via Odoo Studio ou en Python, et des cas pratiques où il apporte un vrai bénéfice métier.
Qu’est-ce que le champ Reference dans Odoo
Dans l’ORM d’Odoo, Reference est un type particulier qui conserve une référence vers un enregistrement d’un des modèles listés dans son paramètre selection. Contrairement à Many2one, il n’est pas fixé sur un seul modèle technique.
En base de données, la valeur d’un champ Reference est une chaîne de caractères au format nom_modele,id_enregistrement. Par exemple, une référence vers la commande de vente 42 sera stockée comme sale.order,42. Cette représentation est importante à connaître si vous effectuez des requêtes SQL directes ou des filtres bas niveau.
Dans l’interface utilisateur, le Reference se présente comme une sélection en deux étapes : choix du type de document (par ex. Commande de vente, Facture, Tâche projet), puis recherche et sélection de l’enregistrement correspondant. Une fois comprise, la manipulation est intuitive pour l’utilisateur.
Voici à quoi ressemble une définition basique d’un champ Reference côté développeur en Python :
from odoo import fields, models
class HelpDeskTicket(models.Model):
_inherit = 'helpdesk.ticket'
related_document = fields.Reference(
selection=[
('sale.order', 'Sale Order'),
('purchase.order', 'Purchase Order'),
('account.move', 'Invoice'),
('project.task', 'Project Task'),
],
string='Related Document',
)
Le paramètre selection est une liste de tuples : chaque tuple associe le nom technique du modèle (comme sale.order) et l’étiquette visible par l’utilisateur. C’est vous qui déterminez les modèles proposés.
Il existe aussi une variante dynamique : la liste selection peut être construite à l’exécution depuis la table ir.model, rendant disponibles tous les modèles installés. Utile pour des outils très configurables, mais il faut la restreindre pour éviter d’embrouiller les utilisateurs.
Dans Odoo Studio, le champ Reference est accessible depuis le panneau de types de champs, sous le nom Reference. En l’ajoutant via Studio, vous choisissez les modèles visibles directement dans l’interface — sans écrire de code. C’est l’option la plus simple pour les personnalisations rapides.
Comment fonctionne ce champ
Bien comprendre comment Reference stocke et résout ses valeurs est essentiel pour l’utiliser correctement dans vos développements Odoo.
Stockage en base de données
Contrairement à Many2one qui enregistre un entier (la clé étrangère), Reference conserve une chaîne composée du nom du modèle et de l’identifiant, par exemple sale.order,15, dans une colonne VARCHAR. La base n’applique donc pas de contrainte de clé étrangère — un choix délibéré pour permettre la polymorphie.
Puisqu’il n’y a pas de contrainte au niveau de la base, Odoo ne supprime pas automatiquement les valeurs Reference quand l’enregistrement cible est effacé. Si une commande de vente est supprimée, la Reference continuera d’afficher la chaîne d’origine. C’est un comportement important à anticiper en développement.
Accéder à l’enregistrement lié en Python
Quand on lit un champ Reference en Python, Odoo renvoie l’objet record correspondant au modèle référencé. Vous pouvez accéder à ses champs comme avec un Many2one. Si le champ est vide, la valeur retournée est False.
ticket = self.env['helpdesk.ticket'].browse(1)
doc = ticket.related_document
if doc:
print(doc._name) # e.g. 'sale.order'
print(doc.name) # e.g. 'S00042'
print(doc.id) # e.g. 15
C’est l’un des points pratiques de l’abstraction ORM d’Odoo : même si la valeur est stockée sous forme de texte, le framework la résout en un objet en lecture dans le code.
Attributs clés du champ
Voici les attributs les plus pertinents que vous pouvez configurer sur un champ Reference dans Odoo :
- selection : Liste de tuples définissant les modèles proposés. Peut aussi être le nom d’une méthode qui retourne cette liste dynamiquement.
- string : L’étiquette affichée à l’utilisateur.
- required : Rend le champ obligatoire. L’utilisateur doit choisir un type et un enregistrement avant d’enregistrer.
- readonly : Empêche la modification depuis l’interface. Pratique quand la référence est définie par du code.
- help : Infobulle expliquant le choix attendu pour guider l’utilisateur.
- compute : Comme tout champ Odoo, Reference peut être calculé via une méthode Python pour être défini automatiquement selon la logique métier.
Filtrage et recherche
Étant stockée comme chaîne, la recherche sur un Reference nécessite de composer cette chaîne dans les domaines. Pour filtrer par document précis, il faut construire la valeur complète :
tickets = self.env['helpdesk.ticket'].search([
('related_document', '=', 'sale.order,15')
])
On peut aussi filtrer par type de modèle avec un opérateur like :
tickets = self.env['helpdesk.ticket'].search([
('related_document', 'like', 'sale.order,')
])
Gardez cette particularité en tête lorsque vous concevez des rapports ou des champs calculés dépendants des Reference : la syntaxe diffère d’un domaine Many2one classique.
Cas d’utilisation métier
Le champ Reference trouve tout son sens lorsque le même lien contextuel doit pouvoir pointer vers des types de documents variés selon la situation. Voici cinq exemples concrets tirés des usages réels.
1. Tickets support liés à n’importe quel document
Une équipe support reçoit des tickets liés à des factures, des livraisons, des contrats ou des commandes. Plutôt que d’avoir un champ par type, un seul Reference sur le ticket permet à l’agent d’attacher le document pertinent en choisissant d’abord le type puis l’enregistrement.
2. Activités CRM liées à diverses sources
Une activité commerciale peut provenir d’un lead, d’un devis, d’un contrat ou d’un dossier support. Un champ Reference sur le modèle d’activité permet de rattacher la source sans enfermer l’utilisateur dans un seul modèle source.
3. Notes transverses entre modules
Certaines entreprises utilisent un modèle de note interne pour consign er des remarques sur différents objets métier. Un Reference permet d’attacher une même note à un client, une tâche projet, un ordre de fabrication ou une commande d’achat, sans multiplier les modèles de notes.
4. Workflow d’approbation générique
Une demande d’approbation peut concerner une commande d’achat, une note de frais, une demande de congé ou un contrat. Mettre un Reference sur le modèle d’approbation centralise le lien vers le document à valider et évite de dupliquer la logique pour chaque type.
5. Notes de frais liées à projet ou commande
Selon la nature du coût, une dépense peut être rattachée soit à un projet client, soit à une commande. Un Reference contenant project.project et sale.order dans sa sélection offre la souplesse nécessaire, très utile en cabinet de conseil ou sociétés de services.
Créer ou personnaliser un champ Reference
Deux approches principales permettent d’ajouter un champ Reference : via Odoo Studio pour du no-code, ou en Python pour un contrôle total.
Utiliser Odoo Studio
Studio simplifie l’ajout d’un Reference : ouvrez Studio sur le formulaire à étendre, ajoutez le champ Reference depuis le panneau, et sélectionnez les modèles à proposer. Studio créera le champ (préfixé x_) sans écrire une ligne de code.
Cette méthode est idéale pour des adaptations rapides ou pour des utilisateurs métiers qui prototypent des formulaires. Attention : les champs créés par Studio peuvent être moins flexibles pour des configurations avancées comme des sélections dynamiques ou des champs calculés complexes.
Implémentation technique en Python
Pour une implémentation développeur complète, définissez le champ Reference en Python. Exemple montrant une sélection dynamique via une méthode :
from odoo import api, fields, models
class ApprovalRequest(models.Model):
_name = 'approval.request'
_description = 'Approval Request'
name = fields.Char(string='Request Name', required=True)
@api.model
def _get_document_types(self):
return [
('purchase.order', 'Purchase Order'),
('hr.expense.sheet', 'Expense Report'),
('hr.leave', 'Time Off Request'),
('sale.order', 'Sale Order'),
]
document_ref = fields.Reference(
selection='_get_document_types',
string='Document',
help='Select the document this approval relates to.',
)
Utiliser une méthode pour selection (en passant son nom) permet d’ajouter une logique conditionnelle : filtrer selon les modules installés, la configuration, ou des droits d’accès, et construire la liste dynamiquement.
Création via l’API XML-RPC
On peut aussi créer un champ Reference via l’API XML-RPC d’Odoo, pratique pour déployer des champs depuis une configuration distante. Le type à passer est reference et la selection s’envoie sous forme de chaîne Python-évaluable :
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_related_document',
'field_description': 'Related Document',
'model_id': model_id,
'ttype': 'reference',
'selection': "[('sale.order', 'Sale Order'), ('purchase.order', 'Purchase Order')]",
'state': 'manual',
}]
)
Attention : via l’API, la valeur selection est transmise comme une chaîne qui pourra être évaluée en Python — c’est le format attendu dans ir.model.fields.
Bonnes pratiques
Directives utiles pour travailler avec les Reference dans votre modèle Odoo.
- Restreindre la liste de sélection. Ne mettez pas tous les modèles possibles par défaut. Limitez-vous aux types de documents pertinents pour l’usage métier : une longue liste déconcerte l’utilisateur.
- Privilégier Many2one si le lien est fixe. Si vous liez toujours le même modèle, Many2one est plus simple, plus efficace en requêtes et mieux supporté pour le reporting.
- Gérer les valeurs nulles dans les champs calculés. Un Reference vide renvoie
Falseen Python. Vérifiez toujours cette condition avant d’accéder aux attributs du document lié. - Nettoyer les références orphelines. Comme la base n’applique pas d’intégrité référentielle, prévoyez une action automatisée ou un cron qui repère et corrige les références pointant vers des enregistrements supprimés.
- Donner des libellés explicites. L’étiquette visible dans le dropdown doit être métier et claire. Affichez «Facture client» plutôt que le nom technique
account.move. - Documenter la décision en technique. Expliquez dans votre spécification pourquoi un Reference a été choisi et quels modèles il couvre : cela évitera les incompréhensions pour les futurs développeurs.
Pièges courants
Voici les erreurs les plus fréquentes quand on découvre le champ Reference.
Penser qu’il se filtre comme un Many2one
Des développeurs écrivent des domaines comme pour un Many2one, par exemple [('document_ref', '=', 15)]. Cela ne fonctionne pas : la valeur en base est une chaîne sale.order,15. Il faut donc composer la chaîne complète pour les filtres.
Oublier que la suppression laisse des valeurs orphelines
Quand un enregistrement référencé est supprimé, la chaîne reste telle quelle. Si une commande est effacée et qu’un ticket contient sale.order,42, la lecture du Reference retournera False au lieu d’erreur — votre code doit gérer ce cas.
Abuser de la sélection dynamique avec tous les modèles
Récupérer tous les modèles depuis ir.model pour remplir la sélection donne souvent une liste trop large pour un champ destiné aux utilisateurs. Préférez une sélection filtrée et pertinente.
Attendre un group-by natif dans les rapports
Comme Reference est stocké en texte, il ne se comporte pas comme une clé étrangère pour les groupements ou pivots natifs d’Odoo. Si vous devez agréger par type de document, créez un champ calculé ou une logique personnalisée qui extrait le nom de modèle dans un champ séparé.
Confondre Reference et Many2one dans Studio
Dans Studio, certains confondent Reference et Many2one parce que les deux relient à d’autres enregistrements. La différence clé : Many2one est fixé à un modèle unique ; Reference laisse l’utilisateur choisir le modèle au remplissage. Si vous avez créé le mauvais type, il faudra recréer le champ.
Conclusion
Le champ Reference comble une lacune du Many2one lorsqu’un lien doit rester flexible entre différents types de documents. Facile à définir, accessible via Studio pour du no-code, et entièrement intégrable dans des modules Python pour des développements plus techniques.
Les points essentiels à retenir sont le format de stockage en chaîne, l’absence de nettoyage automatique lors de suppressions, et la nécessité de composer des chaînes pour les filtres. Une fois ces différences assimilées, le Reference devient un outil fiable dans votre modèle de données Odoo.
Que vous construisiez un workflow d’approbation générique, que vous rattachez des tickets de support à divers documents, ou que vous conceviez un système de notes transversal, le champ Reference permet d’éviter la duplication logique tout en gardant une architecture propre et maintenable.
Besoin d’aide pour votre implémentation Odoo ?
Chez Dasolo, nous accompagnons les entreprises pour implémenter, personnaliser et optimiser Odoo selon leurs processus réels. Que ce soit pour définir une architecture de données, développer des champs et logiques sur-mesure, ou étendre une installation existante, notre équipe détient l’expertise nécessaire pour le faire correctement.
Si votre projet Odoo soulève des questions sur les types de champs, l’architecture ou les bonnes pratiques de développement, contactez-nous. Nous pouvons analyser votre besoin et recommander la solution la plus adaptée.