Étape 2 sur 4 · environ 20 min

Afficher les formations sans contourner les droits

La route Website cherchera les formations avec les droits de l’utilisateur connecté. Chaque carte pourra ensuite ouvrir la fiche du record dans le back-office Odoo 19.

1. Remplacez le contrôleur par la version du laboratoire

La section 2 a préparé une première route. Relisez maintenant le fichier complet. La méthode accepte uniquement un GET, exige une session et utilise l’environnement ORM de la requête en cours.

custom_addons/elearning_portal/controllers/main.py
from odoo import http
from odoo.http import request


class ElearningPortalController(http.Controller):
    @http.route(
        "/formations",
        type="http",
        auth="user",
        website=True,
        methods=["GET"],
    )
    def formations_page(self):
        modules = request.env["elearning.module"].search([], order="name")
        return request.render(
            "elearning_portal.formations_page",
            {"modules": modules},
        )
  • auth="user" exige une session Odoo connectée. Pour lire ce model, la personne doit aussi être un utilisateur interne membre d’un groupe couvert par l’ACL, ici base.group_user.
  • website=True place la route dans le contexte Website et permet au template d’utiliser website.layout.
  • request.env["elearning.module"] emploie l’utilisateur et le contexte de la requête en cours.
  • search([], order="name") lit les formations autorisées et les classe par nom.
Aucun privilège supplémentaire

N’ajoutez pas sudo(). Si l’utilisateur ne possède pas le droit de lire elearning.module, l’accès doit rester refusé. Corrigez l’ACL ou utilisez le bon compte interne au lieu de contourner la règle.

À observer après le redémarrage : un GET sur /formations appelle formations_page(). Une personne sans session est envoyée vers la connexion. Un compte connecté mais non autorisé ne reçoit pas les formations.

2. Vérifiez les deux imports

Le fichier du contrôleur doit être importé par son package, puis ce package doit être importé à la racine de l’addon.

custom_addons/elearning_portal/controllers/__init__.py
from . import main
custom_addons/elearning_portal/__init__.py
from . import controllers
from . import models

Résultat attendu : au prochain redémarrage d’Odoo, Python charge le contrôleur et enregistre la route. Un simple rechargement du navigateur ne suffit pas après une correction d’import.

3. Transmettez uniquement ce que le template doit parcourir

Le contexte contient la clé modules et le recordset des formations. Il ne contient ni clé notes, ni note_ids préparé à part, ni contenu de note.

Le recordset reste côté serveur. Le navigateur reçoit uniquement le HTML produit par QWeb à partir des expressions du template. À l’étape suivante, vous afficherez module.name et module.description, jamais module.note_ids.

Frontière observable

La même formation garde ses relations dans le back-office. La page Website en présente seulement le nom, la description et un lien interne. Une relation disponible dans l’ORM n’est pas automatiquement publiée dans le HTML.

4. Utilisez l’URL actuelle du client web Odoo 19

L’action créée dans la section 1 possède l’external ID elearning_portal.elearning_module_action. Odoo 19 accepte cet external ID dans le chemin, suivi de l’identifiant numérique du record :

Forme du lien vers une fiche interne Odoo 19
/odoo/action-elearning_portal.elearning_module_action/<ID_DE_LA_FORMATION>

Dans QWeb, le record courant fournira cet identifiant :

custom_addons/elearning_portal/views/templates.xml · lien à placer dans la carte
<a class="btn btn-outline-primary mt-3"
   t-att-href="'/odoo/action-elearning_portal.elearning_module_action/%s' % module.id">
    Ouvrir la fiche interne
</a>

action-elearning_portal.elearning_module_action indique à Odoo quelle action ir.actions.act_window charger. Le dernier segment indique quel record ouvrir. Comme l’action propose list,form et qu’un record précis est demandé, le client ouvre sa form view.

N’utilisez pas l’ancien fragment du client web

Le routeur actuel d’Odoo 19 représente une action et son record par des segments sous /odoo/. Gardez la forme vérifiée ci-dessus au lieu de construire un fragment avec id, model et view_type.

Le lien ne donne aucun droit. Il fonctionne seulement avec une session interne capable de lire elearning.module. Après un clic, Odoo recharge l’action, le record et ses views sous les droits de cette même session.

5. Faites un contrôle avant le template

  • custom_addons/elearning_portal/controllers/main.py — contrôlez la route — les valeurs attendues sont auth="user", website=True et methods=["GET"].
  • custom_addons/elearning_portal/controllers/main.py — contrôlez la recherche — l’expression attendue commence par request.env["elearning.module"], sans sudo().
  • custom_addons/elearning_portal/controllers/main.py — contrôlez le contexte — la seule collection transmise est {"modules": modules}.
  • custom_addons/elearning_portal/views/elearning_module_views.xml — contrôlez l’action — l’ID attendu est elearning_module_action.
Résultat attendu

Le contrôleur est importé, la route respecte la session et les ACL, aucune note n’est préparée pour le Website et la forme du lien cible une vraie fiche back-office Odoo 19.