Ce que tu vas apprendre
MVC Odoo
L'architecture Modèle-Vue-Contrôleur adaptée par Odoo et son ORM.
Cycle de requête
Ce qui se passe entre le clic utilisateur et l'affichage de la réponse.
Structure module
Les fichiers obligatoires et l'anatomie d'un module Odoo 19.
Scaffold helpdesk
Créer le squelette du module helpdesk avec la commande scaffold.
- Avoir lu l'article T05 (première approche du développement)
- Un environnement Odoo 19 fonctionnel (T01, T02 ou T03)
- Un IDE configuré (T04) — optionnel mais recommandé
L'architecture MVC d'Odoo
Odoo utilise une variante du pattern MVC classique. L'ORM est la couche centrale qui traduit les objets Python en tables PostgreSQL.
Le navigateur envoie des requêtes HTTP au Controller. Celui-ci interagit avec le Model (via l'ORM) et rend la View.
1 — Le MVC d'Odoo expliqué
Le pattern MVC (Model-View-Controller) sépare les données, la présentation et la logique. Odoo l'adapte à sa manière :
| Couche | Rôle | Fichiers | Langage |
|---|---|---|---|
| Model (M) | Définit les données et la logique métier : champs, méthodes, contraintes, workflows | models/*.py |
Python |
| View (V) | Définit la présentation : formulaires, listes, kanban, recherche, menus, actions | views/*.xml |
XML / QWeb |
| Controller (C) | Gère le routage HTTP, l'authentification, l'exécution des actions | controllers/*.py |
Python |
2 — L'ORM : le cœur d'Odoo
L'ORM (Object-Relational Mapping) est la couche qui traduit les objets Python en tables PostgreSQL. Tu ne manipules jamais le SQL directement — l'ORM s'en charge.
Les 5 opérations fondamentales (CRUD + Search)
# Créer un enregistrement
ticket = self.env['helpdesk.ticket'].create({
'name': 'Bug formulaire contact',
'priority': 'high',
})
# Lire des champs
print(ticket.name) # 'Bug formulaire contact'
# Rechercher des enregistrements
tickets = self.env['helpdesk.ticket'].search([
('priority', '=', 'high'),
('state', '=', 'open'),
])
# Modifier un enregistrement
ticket.write({'state': 'in_progress'})
# Supprimer un enregistrement
ticket.unlink()
- Génère automatiquement les requêtes SQL (INSERT, SELECT, UPDATE, DELETE)
- Gère le cache pour éviter les requêtes inutiles
- Applique les droits d'accès (ACL + record rules)
- Déclenche les contraintes et les onchange
- Met à jour les champs calculés automatiquement
- Gère les transactions (rollback en cas d'erreur)
Le mapping Modèle ↔ Table
| Concept Python | Concept PostgreSQL | Exemple |
|---|---|---|
Modèle (_name) | Table | helpdesk.ticket → helpdesk_ticket |
Champ (fields.*) | Colonne | fields.Char('name') → VARCHAR |
| Enregistrement | Ligne (row) | ticket.id = 42 |
| Recordset | Résultat d'une requête | self.env['...'].search([]) |
3 — Le cycle de requête
Voici ce qui se passe quand un utilisateur clique sur "Nouveau ticket" dans Odoo :
1. NAVIGATEUR → Requête HTTP POST /web/dataset/call_kw
Body: { model: "helpdesk.ticket", method: "create", args: [{...}] }
2. ODOO HTTP → Reçoit la requête, vérifie l'authentification (session cookie)
3. CONTROLLER → Route la requête vers la méthode ORM appropriée
4. SÉCURITÉ → Vérifie les droits d'accès (ACL) et les record rules
5. ORM → Exécute la méthode create() sur le modèle helpdesk.ticket
├─ Valide les contraintes Python et SQL
├─ Déclenche les @api.onchange et @api.depends
└─ Génère le SQL : INSERT INTO helpdesk_ticket (...)
6. POSTGRESQL → Exécute le SQL, retourne l'ID du nouvel enregistrement
7. ORM → Retourne le recordset au controller
8. CONTROLLER → Sérialise la réponse en JSON
9. NAVIGATEUR → Reçoit la réponse, OWL met à jour l'interface
4 — Anatomie d'un module Odoo 19
Un module Odoo est un répertoire Python qui contient des fichiers organisés par convention :
odooskills_helpdesk/
├── __init__.py # Imports Python du module
├── __manifest__.py # Métadonnées (nom, version, dépendances)
├── models/
│ ├── __init__.py # Imports des modèles
│ └── helpdesk_ticket.py # Définition du modèle
├── views/
│ └── helpdesk_ticket_views.xml # Vues (form, list, kanban, search)
├── security/
│ └── ir.model.access.csv # Droits d'accès (ACL)
├── data/
│ └── helpdesk_data.xml # Données initiales (séquences, catégories...)
├── static/
│ └── description/
│ └── icon.png # Icône du module (128x128)
└── README.md # Documentation
Les 2 fichiers obligatoires
1. __init__.py — Point d'entrée Python du module.
Importe les sous-dossiers :
from . import models
2. __manifest__.py — Carte d'identité du module.
Odoo le lit pour savoir comment installer le module :
{
'name': 'OdooSkills Helpdesk',
'version': '19.0.1.0.0',
'category': 'Services/Helpdesk',
'summary': 'Gestion de tickets de support technique',
'author': 'OdooSkills',
'website': 'https://www.odooskills.com',
'license': 'LGPL-3',
'depends': ['base', 'mail'],
'data': [
'security/ir.model.access.csv',
'views/helpdesk_ticket_views.xml',
],
'installable': True,
'application': True,
}
depends— Liste des modules dont celui-ci dépend. Ils seront installés automatiquement.baseest toujours implicite mais c'est une bonne pratique de le déclarer.data— Fichiers XML/CSV chargés à l'installation et à la mise à jour. L'ordre compte : les fichiers sont chargés séquentiellement.application— SiTrue, le module apparaît dans la liste des Applications (avec une icône et une description).license—LGPL-3pour Community,OEEL-1pour Enterprise.
5 — Créer le module helpdesk avec scaffold
Odoo fournit une commande scaffold qui génère le squelette d'un module.
On va l'utiliser pour créer notre module fil rouge.
# Linux
/opt/odoo19/venv/bin/python3 /opt/odoo19/odoo/odoo-bin scaffold odooskills_helpdesk /opt/odoo19/custom-addons/
# Windows
python C:\odoo19\odoo\odoo-bin scaffold odooskills_helpdesk C:\odoo19\custom-addons\
La commande crée :
custom-addons/odooskills_helpdesk/
├── __init__.py
├── __manifest__.py
├── controllers/
│ ├── __init__.py
│ └── controllers.py
├── demo/
│ └── demo.xml
├── models/
│ ├── __init__.py
│ └── models.py
├── security/
│ └── ir.model.access.csv
└── views/
├── templates.xml
└── views.xml
Nettoyer et adapter le scaffold
Le scaffold génère du code générique. On le remplace par notre manifest propre.
Remplace __manifest__.py par :
{
'name': 'OdooSkills Helpdesk',
'version': '19.0.1.0.0',
'category': 'Services/Helpdesk',
'summary': 'Module fil rouge — Gestion de tickets de support',
'description': """
Module développé tout au long de la série d'articles techniques OdooSkills.
Chaque article ajoute des fonctionnalités : modèles, vues, héritage, sécurité, etc.
""",
'author': 'OdooSkills',
'website': 'https://www.odooskills.com',
'license': 'LGPL-3',
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
],
'installable': True,
'application': True,
}
Remplace models/models.py par models/helpdesk_ticket.py :
from odoo import models, fields
class HelpdeskTicket(models.Model):
_name = 'helpdesk.ticket'
_description = 'Ticket de support'
name = fields.Char(string='Sujet', required=True)
Mets à jour models/__init__.py :
from . import helpdesk_ticket
Mets à jour security/ir.model.access.csv :
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_helpdesk_ticket,helpdesk.ticket.user,model_helpdesk_ticket,base.group_user,1,1,1,1
6 — Tester l'installation du module
Vérifie que le module s'installe correctement :
# Linux
/opt/odoo19/venv/bin/python3 /opt/odoo19/odoo/odoo-bin \
-c /opt/odoo19/odoo.conf \
-i odooskills_helpdesk \
-d odoo19_dev \
--stop-after-init
# Windows
python C:\odoo19\odoo\odoo-bin -c C:\odoo19\odoo.conf -i odooskills_helpdesk -d odoo19_dev --stop-after-init
Si tout est correct, tu vois :
INFO odoo19_dev odoo.modules.loading: Loading module odooskills_helpdesk
INFO odoo19_dev odoo.modules.loading: Modules loaded.
Vérifie dans Odoo :
- Active le mode développeur (
?debug=1) - Va dans Paramètres → Technique → Modèles
- Cherche
helpdesk.ticket - Tu devrais voir le modèle avec le champ
name
- URL backend : le préfixe est
/odoo/(plus/web#). Le routage est géré par le nouveau système de chemins propres. - OWL natif : tout le frontend est en OWL (pas de jQuery).
Les composants utilisent
@odoo/owl. - Contraintes : les
_sql_constraintssont remplacées par des attributs de classe :_unique_name = models.Constraint('UNIQUE(name)', "...") - Vues :
treeest renommélistdansview_mode.
Récapitulatif
| Concept | En pratique |
|---|---|
| Model (M) | Classe Python dans models/*.py — définit les données et la logique |
| View (V) | Fichier XML dans views/*.xml — définit la présentation |
| Controller (C) | Géré automatiquement par le framework (rarement écrit manuellement) |
| ORM | Couche qui traduit Python ↔ SQL (create/read/write/unlink/search) |
| Manifest | __manifest__.py — carte d'identité du module |
| Scaffold | odoo-bin scaffold nom_module chemin/ |
État du module helpdesk après cet article
odooskills_helpdesk/
├── __init__.py ✓
├── __manifest__.py ✓ (name, version, depends, application)
├── models/
│ ├── __init__.py ✓
│ └── helpdesk_ticket.py ✓ (1 modèle, 1 champ : name)
└── security/
└── ir.model.access.csv ✓ (accès CRUD pour base.group_user)
Pour aller plus loin
- Odoo Shell : teste l'ORM directement :
self.env['helpdesk.ticket'].create({'name': 'Test'}) - psql : vérifie la table créée :
\d helpdesk_ticket - Code source Odoo : explore
odoo/odoo/models.pypour voir l'implémentation de l'ORM
Liens utiles
Télécharge le Guide Technique Odoo 19
Architecture, pièges v19, checklist premier module — tout dans un PDF gratuit.
Télécharger le guide← Première approche du développement Article suivant de la série : Gestion des bases de données →