1. Créez le model de formations
Créez un fichier dédié. ElearningModule est le nom de la classe Python ; elearning.module est le nom technique du model dans l’ORM. Chaque record de ce model correspond à une formation.
from odoo import fields, models
class ElearningModule(models.Model):
_name = "elearning.module"
_description = "Formation eLearning"
_order = "name"
name = fields.Char(string="Nom", required=True)
description = fields.Text(string="Description")
note_ids = fields.Many2many(
"training.note",
string="Notes associées",
)Le premier paramètre de Many2many désigne le model existant. Odoo créera une table de relation pour mémoriser chaque paire « formation–note ». Les titres et les contenus restent, eux, dans la table training_note.
training.noteNe recopiez pas la classe du jour 2 et ne créez pas un nouveau field title dans cet addon. training_hello charge déjà ce model ; grâce à la dépendance, vous pouvez l’utiliser dans le field note_ids.
À observer : une formation pourra être liée à plusieurs notes et une même note pourra servir à plusieurs formations. Supprimer un lien ne supprime pas automatiquement la note.
2. Indiquez à Odoo où trouver le model
Pour qu’Odoo charge votre model, Python doit suivre les imports jusqu’au fichier qui contient la classe. Remplacez le contenu des deux fichiers d’import par les lignes suivantes.
from . import elearning_modulefrom . import modelsLe fichier racine importe le package models, qui importe ensuite elearning_module.py. C’est ainsi qu’Odoo finit par charger votre classe.
Résultat attendu : au prochain redémarrage, Odoo pourra enregistrer le model elearning.module. Vous n’importez pas encore de contrôleur, puisqu’aucune route n’existe à ce stade.
3. Ajoutez deux formations de démonstration
Les trois notes de départ possèdent déjà des external IDs stables. Le scaffold ne crée pas toujours le dossier data/ : s’il manque, créez custom_addons/elearning_portal/data/, puis ajoutez le fichier suivant. Il définit deux formations fictives liées à ces notes connues.
<?xml version="1.0" encoding="UTF-8"?>
<odoo noupdate="1">
<record id="elearning_module_odoo_basics" model="elearning.module">
<field name="name">Bases du développement Odoo</field>
<field name="description">Comprendre un model, ses données et sa mise à niveau.</field>
<field name="note_ids"
search="[('id', 'in', [
ref('training_hello.training_note_welcome'),
ref('training_hello.training_note_observe'),
])]"/>
</record>
<record id="elearning_module_safe_practice" model="elearning.module">
<field name="name">Pratiquer dans une base d’exercice</field>
<field name="description">Tester les changements sans utiliser de données réelles.</field>
<field name="note_ids"
search="[('id', 'in', [
ref('training_hello.training_note_test'),
])]"/>
</record>
</odoo>La propriété search demande à Odoo de retrouver les notes indiquées. Chaque ref(...) transforme un external ID en identifiant de record ; le préfixe training_hello. est indispensable, car les notes appartiennent à l’autre addon. Odoo associe ensuite les résultats de cette recherche à note_ids.
Vous n’avez pas besoin d’apprendre les commandes relationnelles à trois nombres dans cette étape. Elles sont utiles plus tard, dans certains cas précis, mais elles n’aident pas à comprendre cette première relation.
noupdate="1" préserve ensuite les ajustements réalisés dans l’interface : une mise à niveau ultérieure ne réécrit pas ces relations de départ.
Odoo charge training_hello avant ce fichier. Il peut donc retrouver les trois external IDs. Le XML ne duplique ni le titre ni le contenu des notes : il enregistre seulement les liens entre les records.
4. Attendez avant de mettre l’addon à niveau
Le fichier de données est prêt. À l’étape suivante, vous créerez d’abord l’ACL, ou Access Control List : c’est le fichier qui indique à Odoo quels utilisateurs peuvent lire ou modifier les formations. Dans cet exercice, il s’agit de custom_addons/elearning_portal/security/ir.model.access.csv. Vous créerez ensuite les views, puis ajouterez tous les chemins à data dans le manifeste. Vous installerez ainsi l’addon d’un seul coup, avec les écrans et les droits nécessaires.
À vérifier maintenant :
custom_addons/elearning_portal/models/elearning_module.pycontient exactement un modelelearning.module;custom_addons/elearning_portal/models/__init__.pyimporteelearning_module;custom_addons/elearning_portal/__init__.pyimportemodels;custom_addons/elearning_portal/data/elearning_module_data.xmlréférence les external IDs préfixés partraining_hello..
Votre code décrit un nouveau model de formations et sa relation avec le model du jour 2. Les fichiers sont prêts, mais vous n’avez encore ni menu ni droit d’accès pour ouvrir ces formations.