Étape 7 sur 7

Ajouter un stylesheet à la page QWeb, puis lire demo/

La page QWeb /training/tags de l'étape 6 est utile, mais son HTML est brut. Nous allons lui donner un stylesheet statique, puis terminer le tour du scaffold avec le dossier demo/.

1. À quoi sert le stylesheet ici ?

À l'étape 6, le contrôleur a rendu la page QWeb /training/tags. Elle montre les tags, mais avec seulement un titre et une liste brute. Un stylesheet ne crée ni model, ni record, ni route : il choisit l'apparence du HTML que le serveur a déjà envoyé.

Nous allons donc styliser cette page QWeb, pas la client action OWL de la section 2. L'objectif est immédiatement visible : la même URL affichera une page lisible avec une carte et des tags distincts.

2. Reliez la page QWeb au stylesheet

Remplacez le template de l'étape 6 par cette version complète. La balise <link> dit au navigateur où charger le CSS ; le chemin commence par le nom technique du module, training_hello.

custom_addons/training_hello/views/templates.xml
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <template id="training_tags_page">
        <html>
            <head>
                <title>Training tags</title>
                <link rel="stylesheet"
                      href="/training_hello/static/src/css/training_tags.css"/>
            </head>
            <body class="training-tags-page">
                <main class="training-tags-card">
                    <h1>Training tags</h1>
                    <ul class="training-tags-list">
                        <li t-foreach="tags" t-as="tag">
                            <t t-out="tag.name"/>
                        </li>
                    </ul>
                </main>
            </body>
        </html>
    </template>
</odoo>
  • body class="training-tags-page" limite le style à cette page URL.
  • training-tags-card désigne le bloc principal ; training-tags-list désigne la liste.
  • Le t-foreach est inchangé : le contrôleur fournit toujours les tags, le template les transforme en HTML, puis le navigateur applique le CSS.

3. Créez le stylesheet

Créez ce fichier à l'emplacement indiqué par la balise <link> :

custom_addons/training_hello/static/src/css/training_tags.css
.training-tags-page {
    margin: 0;
    min-height: 100vh;
    padding: 3rem 1.5rem;
    background: #f3f6fa;
    color: #17233f;
    font-family: system-ui, sans-serif;
}

.training-tags-card {
    max-width: 42rem;
    margin: 0 auto;
    padding: 2rem;
    border: 1px solid #cbd5e1;
    border-radius: .75rem;
    background: #fff;
    box-shadow: 0 .5rem 1.5rem rgb(15 23 42 / 8%);
}

.training-tags-list {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    padding: 0;
    list-style: none;
}

.training-tags-list li {
    padding: .45rem .75rem;
    border-radius: 999px;
    background: #e7efff;
    color: #1557ad;
    font-weight: 700;
}

Le préfixe training-tags- évite qu'une règle comme li ou h1 modifie par accident une autre page. Les tags gardent leurs données et leurs droits : seuls leur fond, leur espacement et leur disposition changent.

4. Chargez-le et vérifiez

Pour cette première petite page, le lien vise directement le fichier sous static/. Il n'y a donc pas d'entrée à ajouter dans assets du manifeste. En revanche, le template QWeb modifié reste chargé depuis data : mettez le module Hello Odoo à niveau après avoir modifié views/templates.xml.

  1. Vérifiez que "views/templates.xml" est toujours présent dans data de custom_addons/training_hello/__manifest__.py.
  2. Mettez le module Hello Odoo à niveau pour enregistrer la nouvelle version du template.
  3. Connectez-vous à Odoo puis ouvrez http://127.0.0.1:8069/training/tags. Rechargez simplement le navigateur après une modification du fichier CSS.
Résultat attendu

La même URL montre le titre Training tags dans une carte blanche centrée. Chaque tag apparaît comme une pastille bleue. Si le HTML apparaît sans style, vérifiez d'abord, dans cet ordre, le chemin du fichier CSS, l'attribut href de la balise <link>, puis rechargez le navigateur.

5. Réduisez la friction : rechargement et mise à niveau

Il n'existe pas de « mise à niveau automatique à chaque sauvegarde » sûre dans Odoo. Une mise à niveau peut réimporter des données XML, modifier des views, des droits, des actions ou le schéma de la base. La lancer sans distinction à chaque modification finirait par masquer les effets de bord au lieu de vous faire gagner du temps.

En revanche, le cycle de développement peut être très court si vous choisissez la bonne action selon le fichier modifié :

Vous modifiez…Action la plus légère
static/src/css/training_tags.cssRechargez simplement la page /training/tags.
Un fichier Python, comme un contrôleurDémarrez Odoo avec --dev=reload : il redémarre son processus quand le fichier Python change.
Un template QWeb déjà chargéAjoutez xml à --dev pour lire le template depuis le fichier XML pendant le développement.
Le manifeste, data, un menu, une action, des droits ou un nouveau modelMettez explicitement le module à niveau.

Pour une installation lancée depuis les sources, ce démarrage réduit fortement les redémarrages manuels :

Démarrage local Odoo · adaptez le nom de la base
./odoo-bin -d <nom_de_votre_base> -u training_hello --dev=xml,reload

-u training_hello effectue une mise à niveau une fois au démarrage. Ensuite, --dev=reload surveille le Python et --dev=xml lit les templates QWeb depuis les fichiers. Ce n'est donc pas une mise à niveau répétée à chaque sauvegarde ; c'est précisément ce qui rend la boucle rapide sans réappliquer aveuglément les données du module.

Exception utile à connaître : si vous avez modifié ce template dans l'interface Odoo elle-même, une mise à niveau ou une initialisation reste nécessaire avant que le fichier XML redevienne la source lue par Odoo.

Avec Docker Compose, gardez command: ["--dev=xml,reload"] dans le service odoo, comme à l'étape 6. Lorsqu'une vraie mise à niveau reste nécessaire, exécutez-la sans recréer le conteneur :

Dossier qui contient docker-compose.yml · adaptez le nom de la base
docker compose exec odoo odoo module upgrade training_hello --database <nom_de_votre_base>
Repère pratique.

Commencez toujours par l'action la plus légère : recharger la page pour le CSS, laisser --dev=reload gérer le Python, puis mettre le module à niveau uniquement quand la base ou le manifeste doit réellement changer. Une fois le model du jour 2 créé, la mise à niveau restera normale : elle fait partie du développement Odoo.

6. Ouvrez demo/demo.xml sans l'activer

Le dernier boilerplate est le fichier custom_addons/training_hello/demo/demo.xml. Il contient cinq records commentés pour le model training_hello.training_hello. Ce model n'existe pas encore dans notre module du jour 1 : c'est précisément pourquoi le scaffold a laissé ces lignes dans un commentaire.

custom_addons/training_hello/demo/demo.xml · extrait commenté
<!--
<record id="object0" model="training_hello.training_hello">
    <field name="name">Object 0</field>
    <field name="value">0</field>
</record>
-->

Ne retirez pas ce commentaire et n'ajoutez pas ce fichier au manifeste aujourd'hui : Odoo ne saurait pas créer un record pour un model absent. Au jour 2, lorsque vous créerez un vrai model et ses fields, vous pourrez remplacer cet exemple par des records fictifs qui correspondent à ce model.

data et demo n'ont pas la même promesse

Entrée du manifesteRôleDans notre module aujourd'hui
dataRecords nécessaires ou utiles au module, chargés par son installation et ses mises à niveau.Les deux tags Contacts de l'étape 2.
demoRecords fictifs réservés à une base créée avec les données de démonstration.Rien à charger : le modèle du scaffold n'existe pas.

Quand le model existera, l'entrée prendra cette forme dans custom_addons/training_hello/__manifest__.py :

custom_addons/training_hello/__manifest__.py · exemple pour plus tard
"demo": [
    "demo/demo.xml",
],
Une base de démonstration n'est pas une base de production.

Les records de demo servent à expliquer, explorer ou tester avec des valeurs fictives. Ils ne doivent contenir ni client réel, ni mot de passe, ni configuration métier attendue en production.

Oui : c'est le rôle de la case « Charger les données de démonstration » lors de la création de la base. Si cette case est cochée, Odoo est en mode démonstration et peut charger les fichiers déclarés dans demo quand le module est installé ou mis à niveau. Si elle ne l'est pas, la liste demo du manifeste n'est pas chargée.

7. Ce que vous emportez au jour 2

Vous avez maintenant distingué quatre rôles : les données XML sous data/ amorcent la base ; une view et une action organisent un écran interne ; un template QWeb produit du HTML côté serveur ; les fichiers sous static/ arrivent dans le navigateur. Le dossier demo/ attend, lui, un model réel et une base de démonstration.