Odoo: Pourquoi vous devez éviter de créer vos propres modèles et privilégier les modèles existants ?

nasser Publié le 10/02/2021 (18:14) GMT

Beaucoup de débutant, lorsqu'ils se lancent dans le développement Odoo, créent souvent des modèles qui existent déjà lorsqu'ils doivent implémenter une nouvelle fonctionnalité. Dans cet article, j'explique pourquoi il faut à tout pris éviter cette pratique.

Le weekend dernier j'ai travaillé sur un projet Odoo: je suis parti d'un module développé par un camerounais pour ajouter 2 fonctionnalités. Avant de commencer, je me suis imprégné du module, je l'ai parcouru pour comprendre son organisation et j'ai lu certaines doctrings pour comprendre ce que faisaient certaines fonctions du module. Lors de mon inspection du code, j'ai repéré un truc bizarre qui a attiré mon attention (Je vous dirai de quoi il s'agit plus bas) puis je me suis dit: <<Ah! si un truc se comporte mal, tu vas gérer ça avec un attribut related>>. 

 

Ensuite, je commence à développer la première fonctionnalité qui consiste à enregistrer un partenaire à travers une fenêtre modale. Je plonge alors dans ma bulle, je code le modèle et la vue avant d'écrire la fonction create() qui sera chargée d'enregistrer le partenaire et j'affiche la fenêtre modale. Subitement, après presqu'une heure et demi de codage, je tombe sur un bug qui va me bouffer 2 heures de ma nuit: j'ai travaillé ce samedi là de minuit à 3 heures du matin.

 

En effet, lorsque je rempli les informations du formulaire et clique sur le bouton <<Enregistrer>> , Odoo m'affiche l'erreur suivante: IntegrityError - null value in column "type" violates not-null constraint. Face à un tel bug assez explicite, je comprend clairement que la colonne type est required , ce qui veut dire que dans mon cas il n'y a aucune donnée dans le formulaire pour cette colonne. Je me mets alors à chercher dans le code et je tombe sur le truc bizarre que j'ai mentionné en début d'article: Il s'agit d'un bout de code comme celui-ci:

 

class CustomPartner(models.Model):

    _name = 'custom.partner'

    _inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']

    _rec_name = 'name'

    _inherits = {"res.partner": "partner_id"}

    _order = 'name asc'

 

    nom = fields.Char('Nom',required=True,size=128, translate=True)

    ...

    partner_id = fields.Many2one('res.partner',

            'Partenaire',

            required=False,

            ondelete="cascade",

            readonly=True,

            states={'brouillon': [('readonly', False)]},

            store=True)

 

Ayant vu ce code, j'ai trouvé bizarre qu'il nomme son modèle 'custom.partner', en plus il fait un héritage du modèle 'res.partner' à partir du champ partner_id. Il faut aussi noter qu'il a ajouté dans ce modèle certains champs qui sont déjà présents dans res.partner à savoir le nom (name) et le compagnie (company_id). À ce moment là je me suis dis: s'il y'a un problème je vais juste utiliser un related pour associer cet enregistrement à res.partner. Je voulais alors écrire ceci

 

class CustomPartner(models.Model):

    _inherit = 'res.partner'

    _rec_name = 'name'

    _order = 'name asc'

 

    nom = fields.Char('Nom',required=True,size=128, translate=True)

    name = fields.Char(related='nom')

    type = fields.Selection(selection_add=[('vip', 'VIP')], default='vip')

 

Losrque j'essayaie, ça ne marchait pas. Il fallait absolument que j'ajoute le type sans avoir à refactorer tout son code tout en conservant l'intégrité du modèle, mais ça ne marchait pas, il y'avait toujours une erreur qui apparaissait sur un champs du modèle res.partner (dans la vue, ou le modèle, ou quelque part ailleurs). 

 

Faut avouer que sa façon de surcharger les modèles n'est pas bonne. 

 

C'est à ce moment que j'ai pris l'initiative de refactorer ça, de retirer le nouveau modèle qu'il a ajouté à tord (je vais expliquer pourquoi) et de faire simplement un héritage de res.partner: ce travail je devais le faire pour 3 autres modèles dont il a fait le même style de surcharge. Heureusement, je l'ai fait le jour suivant, c'était dimanche.

 

Solution au problème: toujours respecter les bonnes pratiques

 

Odoo est un ERP assez stable et qui donne la possibilité de tout personnaliser. La bonne nouvelle c'est qu'on peut tout faire avec Odoo et la mauvaise c'est que l'excès de personnalisation va faire souffrir votre projet.

 

Dans le cas que j'ai expliqué plus haut, il s'agissait d'une mauvaise utilisation de l'héritage: le développeur a écris son propre modèle de partenaire parce qu'il veut ajouter les partenaires VIP. Au lieu d'utiliser res.partner et d'ajouter un type à ce modèle, il a fait autrement. Par conséquent, certaines personnalisations étaient bloquées, en l'occurence les miennes. Et si je continuais en faisant par exemple un règlement à travers le modèle account.move, il y'aurait sûrement eu un problème, puisqu'Odoo utilise res.partner à ce niveau.

 

Pour vous simplifier la tâche,

  • ne créez votre propre modèle que si vous êtes persuadés que ce modèle n'existe pas et qu'il n'y a pas son équivalent sur Odoo ou dans un module de l'OCA (Odoo Community Association)
  • lorsque vous avez besoin de mettre en place un nouvelle fonctionnalité, aller sur GitHub ou sur Odoo App Store pour voir si elle existe ou pas. Si elle existe, utilisez le module que vous venez de découvrir. Je vous conseille toujours de privilégier les modules de l'OCA aux modules individuels, parce que ceux de l'OCA sont maintenus par une large communauté.
  • s'il arrive que vous ayez besoin d'un modèle pour vos produits et services, utilisez les modèles product.template et product.product
  • Si vous avez besoin d'un autre pour les commandes, les modèles sale.order et sale.order.line
  • Pour les écritures comptables et factures: account.move et account.move.line
  • Pour les inventaire: stock.inventory, stock.move, stock.move.line
  • etc...
  •  

En conclusion, la documentation officielle d'Odoo est là pour vous servir: lisez là et réfléchissez bien avant de créer votre modèle. Surtout respectez les standards présents dans Odoo Guidelines.

 

kiswayodg 10/01/2023 (18:53) GMT
Superbe article pour débutants


Nial04 05/09/2023 (19:23) GMT
Merci beaucoup pour ce partage, tu relates là les erreurs que beaucoup ont fait (Moi y compris ) lors des débuts sur Odoo :).

Pour ma part je reste persuader que en plus de prendre en compte l'héritage dans les devs, tous développeurs sur Odoo devraient maîtriser à minima le fonctionnement des modules phare Odoo (Accounting, Inventory, Manufacturing, Point of sale...). 



18805b13-6309-418f-9285-db93ea6d1d7f 13/12/2024 (10:48) GMT
Pour ma part, je ne pense pas que le code à l'origine soit une erreur dans la conception (peut être dans le code, mais pas la conception!). Tout au moins, cela se discute.
J'ai travaillé de nombreuses années sur une version 8 qui au fil des ans, l'héritage classique au sens Odoo, nous a amené à avoir un res.partner avec des centaines de champs avec une compréhension du modèle qui devient difficile et dont la migration devient très complexe. Aujourd'hui, nous repensons le modèle pour justement éviter l'héritage classique d'Odoo (en Odoo 17) et, à peu de chose près, le code que l'on voit plus haut correspond à ce qu'il faudrait faire. Le codeur à l'origine a certainement voulu faire une conception Objet afin de pouvoir typer les modèles et de ne pas polluer d'innombrables datas dans la seule table res.partner.
On peut évidemment le faire et cela reste la solution la plus évidente dans un premier temps (faire un _inherit simple), mais on le paye quelques années plus tard.

Dans une conception plus élaborée, on utilise l'abstraction tout en faisant un _inherits (par exemple sur res.partner). Ensuite on construit des modèles spécialisés qui héritent de la classe abstraite. Ainsi, on ne vient pas polluer le modèle res.partner et on peut créer des modèles qui spécialisent des caractéristiques particulières d'une personne. Elle peut être VIP, Manager, et tout ce que l'on veut. Les données sont alors stockées dans des tables distinctes (res.partner.vip, ...) sans à avoir à embarquer tous les champs du modèles res.partner. C'est bien plus propre et réutilisable à souhait.

On perd un peu de temps à mettre en place tout ceci dans un premier temps, mais le gain devient significatif par la suite.

Je ne pense donc pas que ce soit une mauvaise utilisation de l'héritage, par contre Ok avec Nasser sur le reste, on ne réinvente pas la roue, on regarde d'abord s'il n'existe pas des modules qui font le taf. Notamment sur OCA, qui sont généralement très bien faits



Veuillez-vous connecter poster un commentaire
Réaliser un projet

🌍 Travaillez avec des experts basés en Afrique


💵 Tarifs abordables et flexibles

🔍 Experts certifiés

🌟 Assistance personnalisée

🤝 Collaboration exceptionnelle