Extends et include dans les templates django
Dans la partie précédente, on a vu les URLs django.
Maintenant, on va voir comment rendre nos templates HTML Django intelligents en créant des blocs de code réutilisables pour nos applications.
Pour ça, on va utiliser les balises extends
et block
avec Django.
On a deux fichiers HTML : un pour afficher une liste de messages et un autre pour afficher les détails d’un message avec tous ses commentaires liés. Cela fait qu’on a plusieurs blocs de code très similaires : le bloc pour afficher un message sur la page d’index, qui est exactement le même que celui pour afficher le message sur la page détail, et puis les commentaires de la page détail qui ressemblent beaucoup à l’affichage d’un message aussi.
Si on veut du CSS dans notre page détail, on va devoir réimporter le fichier CSS à chaque fois. Donc, à ce stade, ce serait mieux d’avoir un fichier qui contient le layout de notre page, avec simplement des blocs HTML pour les parties qui changent, sans devoir tout réécrire à chaque fois.
Création du fichier de base
C’est là que les notions de extends
et block
vont nous être utiles. On va commencer par créer un fichier qui servira de base pour la structure de nos pages HTML. Ce fichier pourra contenir tout ce qui reste sur nos pages, comme un header avec une barre de navigation, un pied de page (footer), et éventuellement un menu à gauche qui se répète.
Créons donc un fichier HTML que j’appellerai base.html
dans le dossier templates de mon application feed. Dans ce fichier base.html
, je vais déclarer la structure de base d’un fichier HTML avec les balises <html>
, <head>
, <body>
, etc. Ensuite, je vais récupérer les blocs HTML qui doivent être communs à toutes nos pages et les mettre dans base.html
.
Ce qui nous intéresse ici, c’est d’importer notre fichier CSS partout. Je reprends donc la balise {% load static %}
de mon fichier index.html
que je vais mettre tout en haut de base.html
. Dans la balise <head>
, je mets ma balise de lien <link>
qui pointe vers le fichier CSS.
Il faut aussi définir où on va avoir le bloc qui contient le contenu des fichiers HTML enfants. Dans base.html
, dans son <body>
, je vais créer un bloc {% block content %}
que je ferme avec {% endblock %}
. C’est là que va apparaître le contenu des autres fichiers HTML, comme index
et details
.
Modification des fichiers enfants
Dans index.html
, je dois ouvrir ce même bloc avec la balise {% block content %}
. Là, je mets toutes mes balises HTML et, tout en bas du fichier, je ferme avec {% endblock %}
. Surtout, je n’oublie pas d’ajouter la balise {% extends 'base.html' %}
en haut de mon fichier, ce qui va permettre à Django de savoir que index.html
est une extension de base.html
.
Vérifions rapidement qu’il n’y a pas de problème : dans mon navigateur, je rafraîchis la page et si tout s’est bien passé, rien n’a changé.
Maintenant, on peut faire la même chose pour le fichier details.html
. Comme pour index.html
, je commence par écrire la balise {% extends 'base.html' %}
, puis j’ouvre le bloc {% block content %}
et je le ferme tout en bas de mon fichier. Je retourne dans mon navigateur et si je vais sur /1
ou n’importe quel ID pour lequel un message existe, ça fonctionne, et en plus, le style CSS a bien été appliqué.
Ajout de la navigation et des messages cliquables
Donc là, on a une structure de base qui est définie dans le fichier base.html
. On va pouvoir créer plein de balises HTML dedans pour améliorer la structure du site. Déjà, j’aimerais avoir des liens en haut de ma page pour naviguer facilement entre ma page d’index et celle de l’administration. Dans base.html
, dans le <body>
, je crée une balise <nav>
. Dans cette balise <nav>
, je mets deux liens : un vers l’accueil avec href="/"
et un autre vers l’admin avec href="/admin"
.
Tant qu’on fait de l’HTML, j’aimerais rendre les messages cliquables, de sorte que, quand on clique dessus, ça nous dirige vers leur page de détail en fonction de leur ID. Pour ça, sur la page index.html
, dans le bloc de code, je change la <div>
en <a>
et j’ajoute un href
qui sera "/{{ message.id }}"
.
Je retourne sur ma page d’index et là, je clique sur un des messages pour voir si je suis bien dirigé vers la page de détail avec le bon message. Super, ça fonctionne ! Mais là, on a exactement le même bloc pour les messages qui se répète dans index.html
et details.html
. J’aimerais pouvoir inclure ce bloc message en une ligne en changeant juste la variable message qu’on lui passe.
Utilisation de la balise include
On peut faire ça avec une autre balise de Django qui est la balise include
. Je vais créer un nouveau fichier que j’appellerai message.html
et dans ce fichier, je copie-colle le bloc qui affiche un message. À la place, je mets une <div>
dans laquelle j’utilise la balise logique {% include 'message.html' %}
. Je dois lui passer un message pour que le fichier message.html
connaisse le contenu d’un message. Je fais ça avec with message=message
.
Je vais faire pareil dans details.html
en remplaçant tout le bloc message avec cette même ligne. Si je retourne dans mon navigateur, je vois que mon site n’a pas changé, ça fonctionne pareil, et ça nous a permis d’enlever pas mal de répétitions.
Ajout d’un formulaire de commentaire
Dans ma page de détail, il manque toujours quelque chose : la capacité de pouvoir commenter un message. Pour ça, il faut que j’ajoute un formulaire. Je vais garder la même logique que pour le bloc message et créer un fichier HTML pour mon formulaire, comme ça je pourrai l’importer facilement dans mes deux fichiers.
Je vais copier mon formulaire qui existe déjà dans la page d’index, le mettre dans mon nouveau fichier form.html
. Là, la seule chose qui va changer, c’est la valeur de la balise action
du <form>
. Dans le cas où on veut créer un tout nouveau message, on doit effectuer l’action POST vers la vue index, mais pour les commentaires, on doit faire ça avec la fonction details.
Dans mon fichier index.html
, là où était le formulaire, je vais mettre un autre include
. Donc je fais une balise <div>
et ensuite une balise logique Django {% include 'form.html' with action='/' %}
. Cela signifie que le formulaire a bien la valeur '/'
, qui est l’action correcte pour le formulaire de notre page d’index.
Implémentation de la logique du formulaire
Maintenant qu’on a cette structure, on peut ajouter un formulaire en une seule ligne sur la page de détail. Ce formulaire aura une action qui sera "/{{ message.id }}/"
pour avoir ça le plus simple, c’est d’utiliser request.path
qu’on peut utiliser dans un template Django.
Maintenant, au niveau HTML, on doit implémenter la logique dans la fonction details
qui se trouve dans le fichier views.py
. Comme pour la fonction index
, dans le cas où notre requête est de méthode POST, on peut récupérer le contenu et l’utilisateur comme on l’avait fait dans index
. D’abord, on vérifie que la méthode HTTP est bien POST avec if request.method == 'POST'
. Ensuite, on récupère le content
pareil que dans notre fonction index
avec content = request.POST.get('content')
, et pour l’utilisateur, on fait user = request.user
.
Pour créer un message, ça va être presque pareil, sauf qu’on doit fournir un response_to
qui sera le message pour lequel on regarde les détails. Donc, faisons message.objects.create(content=content, user=user, response_to=message)
. On peut récupérer le message avec message.objects.get(id=id)
, ou encore plus simplement, on peut lui passer l’ID directement avec response_to_id=id
.
Vérification finale
Maintenant qu’on a fait ça, on peut se rendre sur le navigateur et vérifier que la page d’index fonctionne toujours pareil, et surtout, la page de détail pour laquelle on vient d’implémenter la logique pour le formulaire. On va se rendre dessus et essayer d’écrire un commentaire pour le message sur lequel on est sur la page de détail. Si tout s’est bien passé, vous devriez voir votre commentaire s’afficher.
Maintenant, on a beaucoup touché à l’HTML, mais le CSS a du retard.
Donc ce qu’on va faire, c’est améliorer le CSS pour rendre notre application encore plus jolie.
Et donc dans la prochaine partie de ce tutoriel, voyons les balises conditionnelles en django pour afficher des éléments HTML en fonction de conditions.
Je m'appelle Thomas, et je code depuis plus de 20 ans. Depuis ma sortie de la première promotion de l'École 42, j'ai conçu et développé des centaines d'applications et de sites web. Sur ce blog, je partage avec vous les stratégies les plus efficaces pour maîtriser l'art de coder et progresser rapidement.