Introduction
Le champ Many2One est l'un des éléments fondamentaux du modèle de données Odoo. Chaque fois que vous liez un bon de commande à un client, assignez un produit à une catégorie ou connectez une tâche à un projet, vous travaillez avec une relation Many2One. C'est le type de champ relationnel le plus courant dans Odoo, et comprendre son fonctionnement est essentiel pour quiconque s'engage dans le développement ou la personnalisation sérieuse d'Odoo.
D'un point de vue commercial, les champs Many2One sont ce qui donne à Odoo sa cohérence en tant que système intégré. Sans eux, chaque module serait une île. Avec eux, les données circulent naturellement d'un enregistrement à un autre, et les utilisateurs peuvent naviguer entre les documents liés sans jamais penser à la structure de la base de données.
Ce guide couvre ce que le champ Many2One stocke, comment il se comporte dans l'ORM Odoo et dans l'interface, comment le créer et le configurer en utilisant Odoo Studio ou Python, et des cas d'utilisation réels provenant de la CRM, des ventes, de l'inventaire et de la comptabilité.
Qu'est-ce que le champ Many2One dans Odoo
Dans l'ORM Odoo, un champ Many2One crée un lien d'un enregistrement à exactement un enregistrement dans un autre modèle. Le nom décrit la relation du point de vue du modèle actuel : de nombreux enregistrements ici peuvent pointer vers un enregistrement là-bas. Par exemple, de nombreux bons de commande peuvent pointer vers un client, et de nombreux produits peuvent appartenir à une catégorie de produit.
Au niveau de la base de données, un champ Many2One stocke une clé étrangère dans la table actuelle. Si un bon de commande est lié à l'ID client 42, la colonne partner_id de la table sale_order contient l'entier 42. Odoo gère automatiquement la jointure et la récupération du nom de l'enregistrement lié.
Dans l'interface utilisateur, un champ Many2One apparaît sous forme de menu déroulant ou d'entrée typeahead. Les utilisateurs peuvent commencer à taper un nom, et Odoo filtre les enregistrements correspondants en temps réel. La sélection d'un enregistrement établit le lien. Le champ affiche le nom de l'enregistrement lié, et non son ID interne. Cela en fait l'un des types de champs les plus naturels du point de vue de l'expérience utilisateur.
Voici à quoi cela ressemble dans une définition de modèle Python :
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
x_account_manager_id = fields.Many2One(
comodel_name='res.users',
string='Responsable de compte',
ondelete='set null',
)
Le paramètre comodel_name est le nom technique du modèle auquel vous vous liez. Le paramètre ondelete contrôle ce qui arrive à l'enregistrement actuel si l'enregistrement lié est supprimé. Les trois options sont cascade (supprimer également l'enregistrement actuel), set null (effacer le lien), et restrict (bloquer la suppression si un enregistrement y pointe).
Dans Odoo Studio, le champ Many2One apparaît sous l'étiquette Many2One dans le sélecteur de champs. Lorsque vous en ajoutez un via Studio, vous choisissez le modèle cible dans une liste, et Studio gère la création du champ. Cela en fait l'un des champs Odoo Studio les plus accessibles pour établir des relations sans écrire de code.
Comment fonctionne le champ
Lorsque vous lisez un champ Many2One via l'ORM Odoo, vous obtenez un ensemble d'enregistrements contenant l'enregistrement lié. Si le champ est vide, vous obtenez un ensemble d'enregistrements vide. En Python, vous pouvez accéder directement à l'enregistrement lié et naviguer vers ses champs en utilisant la notation par points :
order = self.env['sale.order'].browse(1)
customer_name = order.partner_id.name
customer_city = order.partner_id.city
Cette navigation en chaîne est l'un des aspects les plus pratiques du cadre Odoo. Vous n'avez pas besoin d'écrire des jointures explicites ou des requêtes séparées. L'ORM gère le travail de base de données en arrière-plan.
Lors de la lecture via l'API XML-RPC, un champ Many2One renvoie une liste avec deux éléments : l'ID entier de l'enregistrement lié et son nom d'affichage. Par exemple, [42, "Acme Corp"]. Si le champ est vide, il renvoie False. Il est important de le savoir lors du traitement des réponses API dans vos scripts.
Attributs clés des champs
Voici les propriétés les plus importantes que vous pouvez configurer sur un champ Many2One dans le cadre Odoo :
- comodel_name: Le nom technique du modèle cible. C'est le seul paramètre requis.
- ondelete: Que se passe-t-il avec l'enregistrement actuel lorsque l'enregistrement lié est supprimé. Les options sont
'cascade','set null', et'restrict'. Par défaut, c'est'set null'. - domain: Un filtre qui restreint les enregistrements que l'utilisateur peut sélectionner dans le menu déroulant. Par exemple,
domain=[('customer_rank', '>', 0)]limite la sélection des partenaires aux clients uniquement. - context: Valeurs de contexte supplémentaires passées lors de l'ouverture de l'enregistrement lié ou du menu déroulant. Utile pour pré-remplir des champs sur des enregistrements liés nouvellement créés.
- required: Rend le champ obligatoire. L'enregistrement ne peut pas être enregistré à moins que ce champ ne soit défini.
- readonly: Empêche les utilisateurs de modifier l'enregistrement lié. Utile lorsque le lien est défini par programme et ne doit pas être modifié manuellement.
- delegate: Lorsqu'il est défini sur
True, tous les champs du modèle lié deviennent directement accessibles sur le modèle actuel. Cela est utilisé pour l'héritage de modèle dans le développement Odoo, pas pour les champs relationnels réguliers.
Comment cela apparaît dans les vues
Dans les vues de formulaire, un champ Many2One se présente sous la forme d'un menu déroulant avec un champ de recherche. Les utilisateurs peuvent taper un nom partiel pour filtrer la liste. Ils peuvent également cliquer sur l'icône de flèche à côté du champ pour ouvrir directement l'enregistrement lié, ce qui est très utile pour naviguer entre les documents liés sans passer par les menus.
Dans les vues de liste, les champs Many2One affichent le nom de l'enregistrement lié. Ils prennent en charge les opérations de regroupement : vous pouvez regrouper une liste de commandes de vente par client, ou une liste de tâches par projet. Ce regroupement est l'une des fonctionnalités les plus utilisées dans les rapports Odoo.
Dans les vues de recherche, les champs Many2One peuvent être utilisés comme filtres et critères de regroupement. Lorsque vous recherchez par client dans le pipeline CRM, vous filtrez sur un champ Many2One.
Le One2Many Réciproque
Chaque relation Many2One a un inverse naturel : le One2Many. Si les commandes de vente sont liées à un client via Many2One, l'enregistrement du client peut exposer une liste de toutes les commandes de vente liées via un champ One2Many. Dans le développement Odoo, il est de bonne pratique de créer les deux côtés de la relation. Cela permet aux utilisateurs de naviguer du formulaire client vers toutes leurs commandes sans effectuer une recherche séparée. Le champ One2Many n'ajoute pas de colonne de base de données ; il est calculé à partir de la clé étrangère Many2One de l'autre côté.
Cas d'utilisation commerciale
Le champ Many2One est omniprésent dans une implémentation standard d'Odoo. Voici cinq exemples pratiques tirés de flux de travail réels.
CRM : Lier les Leads aux Commerciaux
Dans le module CRM d'Odoo, chaque lead ou opportunité a un champ user_id, qui est un Many2One pointant vers res.users. C'est le commercial responsable du lead. Les managers peuvent filtrer le pipeline par commercial, voir les taux de conversion par représentant et attribuer des leads en masse. Le champ Many2One rend ce type de segmentation et de reporting possible sans développement personnalisé. Si vous souhaitez ajouter un deuxième commercial ou un champ de gestionnaire de compte dédié, vous ajoutez simplement un autre champ Many2One pointant vers le même modèle.
Ventes : Connecter les Commandes aux Clients et aux Tarifs
Une commande de vente dans Odoo a au moins deux champs Many2One importants : partner_id (le client, lié à res.partner) et pricelist_id (la liste de prix, liée à product.pricelist). Lorsque un commercial sélectionne un client, Odoo peut automatiquement remplir la liste de prix, les conditions de paiement et l'adresse de livraison en fonction de l'enregistrement du client. Cette population automatique est pilotée par des méthodes onchange qui lisent la valeur Many2One et remplissent les champs associés. C'est l'un des avantages les plus visibles d'un modèle de données Odoo bien structuré.
Inventaire : Produits et Catégories
Chaque produit dans Odoo appartient à une catégorie de produit via un champ Many2One (categ_id sur product.template). La catégorie de produit contrôle les comptes comptables pour le coût des biens vendus et les revenus, les méthodes d'évaluation et les stratégies de retrait dans les entrepôts. Obtenir l'attribution de la catégorie correcte sur chaque produit est essentiel pour un reporting financier correct. Un champ Many2One rend cette attribution simple : un menu déroulant par produit, un enregistrement de catégorie partagé entre des centaines de produits.
Comptabilité : Écritures Comptables et Journaux
Chaque écriture comptable dans Odoo est liée à un journal comptable via un champ Many2One (journal_id sur account.move). Le journal détermine la séquence utilisée pour la numérotation des documents, le type d'écriture (vente, achat, banque, espèces, divers), et dans certains cas, les comptes de débit et de crédit par défaut. Sélectionner le mauvais journal sur une facture fournisseur ou un paiement crée des écritures dans la mauvaise section du grand livre. Le champ Many2One ici n'est pas seulement une commodité ; c'est un point de contrôle pour l'exactitude comptable.
Gestion de Projet : Tâches et Projets
Dans le module Projet d'Odoo, chaque tâche appartient à un projet via un champ Many2One (project_id sur project.task). Ce lien unique détermine quelle progression d'étape la tâche suit, quels membres de l'équipe peuvent y accéder, et comment les feuilles de temps sont allouées. Pour les entreprises de services professionnels facturant par projet, le lien Many2One entre les feuilles de temps, les tâches et le projet parent est l'épine dorsale de la reconnaissance des revenus et des flux de travail de facturation.
Créer ou personnaliser le champ Many2One
Il existe trois principales façons d'ajouter un champ Many2One à un modèle Odoo, en fonction de votre contexte technique et de votre approche de déploiement.
Utiliser Odoo Studio (Sans Code)
Odoo Studio est l'outil de personnalisation intégré à faible code. Pour ajouter un champ Many2One sans écrire de code :
- Ouvrez Odoo Studio depuis le menu principal.
- Naviguez vers le formulaire où vous souhaitez ajouter le champ.
- Faites glisser un champ Many2One depuis le sélecteur de champs vers le formulaire.
- Dans le panneau des propriétés, choisissez le modèle cible dans la liste.
- Définissez l'étiquette et tout filtre de domaine optionnel pour restreindre les enregistrements que les utilisateurs peuvent sélectionner.
- Enregistrez et fermez Studio.
Studio crée le champ avec un préfixe x_studio_ et l'ajoute automatiquement à la vue du formulaire. Le champ est immédiatement fonctionnel : les utilisateurs peuvent ouvrir le menu déroulant, rechercher des enregistrements liés et en sélectionner un. C'est l'une des façons les plus rapides d'étendre un formulaire avec un lien relationnel, et cela ne nécessite aucune connaissance technique au-delà de la compréhension de ce que représentent les deux modèles dans votre entreprise.
Utiliser Python dans un module personnalisé
Pour les développeurs construisant des modules Odoo, les champs Many2One sont définis directement en Python. C'est l'approche recommandée pour tout développement Odoo qui doit être contrôlé par version et déployé sur plusieurs environnements :
from odoo import fields, models
class ProjectTask(models.Model):
_inherit = 'project.task'
x_client_contact_id = fields.Many2One(
comodel_name='res.partner',
string='Contact Client',
domain=[('type', '=', 'contact')],
ondelete='set null',
help='Le contact principal chez le client pour cette tâche.',
)
Après avoir défini le champ dans le modèle, incluez-le dans la vue XML pertinente et exécutez une mise à niveau pour appliquer les modifications de la base de données. Cette approche donne un contrôle total sur les filtres de domaine, le comportement ondelete et l'intégration avec les méthodes de calcul et les contraintes. C'est l'approche standard du guide des développeurs Odoo pour les champs relationnels dans les modules de production.
Lors de la création d'un Many2One dans le cadre de la personnalisation d'Odoo, il est également bon de pratique d'ajouter le champ One2Many correspondant sur le modèle lié afin que les utilisateurs puissent naviguer dans les deux sens de la relation :
class ResPartner(models.Model):
_inherit = 'res.partner'
x_task_ids = fields.One2Many(
comodel_name='project.task',
inverse_name='x_client_contact_id',
string='Tâches Associées',
)
Utilisation de l'API XML-RPC
Si vous gérez les personnalisations Odoo de manière programmatique, par exemple via un script de déploiement ou un carnet de configuration à distance, vous pouvez créer des champs Many2One via l'API XML-RPC :
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_client_segment_id',
'field_description': 'Segment Client',
'model_id': model_id,
'ttype': 'many2one',
'relation': 'res.partner.category',
'on_delete': 'set null',
'state': 'manual',
}]
)
La clé relation spécifie le modèle cible. La clé on_delete définit le comportement de suppression. Lors de la création via l'API, n'oubliez jamais de créer également le champ One2Many réciproque sur le modèle lié afin que la navigation fonctionne des deux côtés de la relation. C'est l'une des règles obligatoires dans les configurations à distance Dasolo pour toute création de champ Many2One.
Meilleures pratiques
1. Créez toujours le One2Many réciproque
Lorsque vous ajoutez un champ Many2One à un modèle, créez également le One2Many correspondant sur le modèle lié. Cela ne vous coûte pas une colonne de base de données supplémentaire, mais cela rend la navigation beaucoup plus naturelle pour les utilisateurs. Sans cela, les utilisateurs n'ont aucun moyen de voir depuis le formulaire client quelles tâches, commandes ou enregistrements personnalisés leur sont liés.
2. Utilisez des filtres de domaine pour restreindre la sélection
Un champ Many2One pointant vers res.partner donne accès à tous les partenaires par défaut, y compris les fournisseurs, les clients, les utilisateurs internes et les adresses de livraison. Si votre logique métier n'a de sens que pour les clients, ajoutez un filtre de domaine comme domain=[('customer_rank', '>', 0)]. Cela réduit le bruit dans le menu déroulant et empêche les utilisateurs de faire des sélections incorrectes qui semblent valides mais produisent de mauvais résultats en aval.
3. Choisissez ondelete avec soin
Le comportement ondelete est plus important qu'il n'y paraît. Utiliser 'cascade' signifie que la suppression de l'enregistrement lié supprimera également tous les enregistrements qui y pointent. Cela peut entraîner des suppressions massives accidentelles si ce n'est pas intentionnel. Dans la plupart des scénarios commerciaux, 'set null' est le choix le plus sûr : cela efface le lien sans supprimer quoi que ce soit. Utilisez 'restrict' lorsque l'enregistrement lié ne doit jamais être supprimé tant que quelque chose y pointe, par exemple une catégorie de produit qui a des produits qui lui sont assignés.
4. Évitez de dupliquer des données qui devraient être un Many2One
Une erreur courante dans les premiers projets de personnalisation Odoo est d'ajouter un champ char pour stocker un nom d'entreprise ou une étiquette de catégorie, alors qu'un Many2One pointant vers un modèle existant serait la bonne approche. Les champs char pour des valeurs qui existent déjà en tant qu'enregistrements dans un autre modèle créent une duplication de données, rendent le filtrage et le regroupement peu fiables, et produisent des incohérences lorsque les noms changent. Si les données dont vous avez besoin se trouvent dans un autre modèle, utilisez un Many2One.
5. Utilisez le contexte pour pré-remplir les enregistrements liés
L'attribut context sur un champ Many2One vous permet de passer des valeurs par défaut lorsque les utilisateurs créent un nouvel enregistrement lié directement à partir du menu déroulant. Par exemple, si un Many2One pointe vers un contact dans un projet, vous pouvez pré-remplir le projet sur le nouvel enregistrement de contact en utilisant le contexte. Cela réduit la saisie manuelle et aide à maintenir la cohérence des données lorsque les utilisateurs créent des enregistrements liés à la volée.
Pièges courants
Oublier le One2Many réciproque
Ajouter un champ Many2One sans créer le One2Many inverse sur le modèle lié est l'oubli le plus courant dans la personnalisation Odoo. Le résultat est un lien unidirectionnel : vous pouvez voir l'enregistrement lié depuis le modèle actuel, mais depuis l'enregistrement lié, vous n'avez aucun moyen de trouver tous les enregistrements qui y pointent. Les utilisateurs commencent à se plaindre qu'ils ne peuvent pas trouver les enregistrements liés, et quelqu'un finit par construire une recherche ou un rapport personnalisé pour compenser l'absence d'un champ inverse.
Utiliser la suppression en cascade sans y réfléchir
Définir ondelete='cascade' sur un Many2One qui lie des enregistrements opérationnels à un enregistrement maître peut entraîner une perte de données sérieuse. Si un utilisateur archive ou supprime une catégorie de produit, et que tous les produits qui y sont liés ont une suppression en cascade, chaque produit de cette catégorie disparaît. Dans la plupart des cas, set null ou restrict est le comportement approprié pour les données commerciales.
Ne pas vérifier pour False lors de la navigation en Python
Lorsqu'un champ Many2One est vide, le lire renvoie un recordset vide en Python, ce qui est faux. Si votre code fait order.partner_id.name sans vérifier si partner_id est défini, il renverra une chaîne vide plutôt que de lever une erreur. Cela est souvent acceptable, mais si vous naviguez plusieurs niveaux en profondeur (order.partner_id.country_id.name) et qu'un lien dans la chaîne est vide, vous obtenez une chaîne vide à la fin, ce qui peut silencieusement produire une sortie incorrecte dans les rapports ou les e-mails. Vérifiez toujours les recordsets vides lorsque le champ n'est pas requis.
Pointer vers le mauvais modèle
Dans Odoo, res.partner est utilisé pour les clients, les fournisseurs, les contacts et les entreprises en même temps. Un Many2One pointant vers res.partner sans filtre de domaine donne accès à tous. Si vous avez prévu le champ uniquement pour les clients mais avez oublié le domaine, les commerciaux verront des utilisateurs internes, des adresses de livraison et des contacts fournisseurs dans le menu déroulant. Définissez toujours un filtre de domaine qui correspond à l'intention commerciale réelle du champ.
Utilisation excessive de Many2One là où un champ de sélection suffirait
Si les valeurs liées sont une liste fixe et petite qui ne change jamais, un champ de sélection est souvent plus simple et plus performant qu'un Many2One. Les champs Many2One nécessitent un modèle séparé avec des enregistrements, et ils ajoutent une jointure de base de données à chaque requête. Pour quelque chose comme un statut avec trois ou quatre options, un champ de sélection est plus propre. Utilisez Many2One lorsque l'ensemble des valeurs possibles est large, géré par des utilisateurs ou partagé entre plusieurs modèles.
Conclusion
Le champ Many2One est au cœur de la façon dont Odoo connecte les données entre les modules. Comprendre cela n'est pas seulement une préoccupation pour les développeurs. Les analystes commerciaux, les consultants fonctionnels et les utilisateurs avancés qui souhaitent étendre Odoo avec Studio bénéficient tous de la connaissance de ce que fait un Many2One, quand en utiliser un et quoi surveiller.
Les points clés à retenir : créez toujours le One2Many réciproque afin que la navigation fonctionne des deux côtés, utilisez des filtres de domaine pour garder les menus déroulants propres et pertinents, choisissez délibérément votre comportement ondelete, et évitez d'utiliser Many2One là où un champ de sélection plus simple ferait le travail.
Que vous configuriez un champ via Odoo Studio, écriviez un module Python personnalisé ou gériez votre modèle de données Odoo via l'API XML-RPC, obtenir les champs relationnels correctement dès le départ rend votre implémentation plus fiable et beaucoup plus facile à maintenir dans le temps.
Chez Dasolo, nous aidons les entreprises à mettre en œuvre, personnaliser et optimiser Odoo dans tous les départements. Que vous ayez besoin d'aide pour concevoir un modèle de données propre, ajouter des champs relationnels à vos formulaires ou construire un module Odoo complet à partir de zéro, notre équipe est là pour vous soutenir. Contactez-nous et parlons de votre projet Odoo.