259 lines
8.9 KiB
TeX
259 lines
8.9 KiB
TeX
\chapter{Templates}
|
|
|
|
Avant de commencer à interagir avec nos données au travers de listes, formulaires et d'interfaces sophistiquées, quelques mots sur les templates: il s'agit en fait de \textbf{squelettes} de présentation, recevant en entrée un dictionnaire contenant des clés-valeurs et ayant pour but de les afficher selon le format que vous définirez.
|
|
|
|
Un squelette de page HTML basique ressemble à ceci:
|
|
|
|
\begin{minted}{html}
|
|
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<title></title>
|
|
</head>
|
|
<body>
|
|
<p>Hello world!</p>
|
|
</body>
|
|
</html>
|
|
\end{minted}
|
|
|
|
Notre première vue permettra de récupérer la liste des objets de type \texttt{Wishlist} que nous avons définis dans le fichier \texttt{wish/models.py}.
|
|
Supposez que cette liste soit accessible \textit{via} la clé \texttt{wishlists} d'un dictionnaire passé au template.
|
|
Cette liste devient dès lors accessible grâce aux tags \texttt{\{\% for wishlist in wishlists \%\}}.
|
|
A chaque tour de boucle, nous pourrons directement accéder à la variable \texttt{\{\{ wishlist \}\}}.
|
|
De même, il sera possible d'accéder aux propriétés de cette objet de la même manière: \texttt{\{\{ wishlist.id \}\}}, \texttt{\{\{ wishlist.description \}\}}, \ldots et d'ainsi respecter la mise en page que nous souhaitons.
|
|
|
|
En reprenant l'exemple de la page HTML définie ci-dessus, nous pouvons l'agrémenter de la manière suivante:
|
|
|
|
\begin{minted}{html}
|
|
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<title></title>
|
|
</head>
|
|
<body>
|
|
<p>Mes listes de souhaits</p>
|
|
<ul>
|
|
{% for wishlist in wishlists %}
|
|
<li>{{ wishlist.name }}: {{ wishlist.description }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</body>
|
|
</html>
|
|
\end{minted}
|
|
|
|
|
|
\begin{figure}[H]
|
|
\centering
|
|
\scalebox{1.0}{\includegraphics[max size={\textwidth}{\textheight}]{images/html/my-first-wishlists.png}}
|
|
\end{figure}
|
|
|
|
\section{Entête, héritage}
|
|
|
|
Plutôt que de réécrire à chaque fois le même entête, nous pouvons nous simplifier la vie en implémentant un héritage au niveau des templates.
|
|
Pour cela, il suffit de définir des blocs de contenu, et d'\emph{étendre} une page de base, puis de surcharger ces mêmes blocs.
|
|
|
|
Par exemple, si on repart de notre page de base ci-dessus, on va y définir deux blocs réutilisables:
|
|
|
|
\begin{minted}{html}
|
|
<!-- templates/base.html -->
|
|
|
|
{% load static %}<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<title>{% block title %}Gwift{% endblock %}</title> <1>
|
|
</head>
|
|
<body>
|
|
{% block body %}<p>Hello world!</p>{% endblock %} <2>
|
|
</body>
|
|
</html>
|
|
\end{minted}
|
|
|
|
Nous avons à présent un bloc \texttt{title} et un bloc \texttt{body}, qui peuvent être surchargés dès qu'une page se définit comme extension de notre page \texttt{base.html}:
|
|
|
|
\begin{minted}{html}
|
|
<!-- templates/wishlist/wishlist_list.html -->
|
|
|
|
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ block.super }} - Listes de souhaits{% endblock %} <2>
|
|
|
|
{% block body %}
|
|
<p>Mes listes de souhaits</p>
|
|
<ul>
|
|
{% for wishlist in wishlists %}
|
|
<li>{{ wishlist.name }}: {{ wishlist.description }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% endblock% %}
|
|
\end{minted}
|
|
|
|
\section{Extensions}
|
|
|
|
Attention: il est primordial que les extensions/tags ne fassent aucune requête en base de données.
|
|
Il est vraiment important que les données (re)travaillées soient disponibles dès que l'appel sera réalisé, sans quoi cela dégradera énormément les performances à l'affichage de la page.
|
|
|
|
Chronologie T -> T+1 -> T+2
|
|
Données affichées: X -> X, Y -> X,Y,Z
|
|
Et ça sera dégueulasse.
|
|
|
|
\subsection{Extensions natives}
|
|
|
|
Django vient avec un ensemble de *tags* ou *template tags*.
|
|
On a vu la boucle \texttt{for} ci-dessus, mais il existe \href{https://docs.djangoproject.com/fr/1.9/ref/templates/builtins/}{beaucoup d'autres tags nativement présents}.
|
|
Les principaux sont par exemple:
|
|
|
|
\begin{itemize}
|
|
\item Les conditions, qui permettent de vérifier un contexte et de n'afficher le contenu d'un bloc que si la condition est vérifiée
|
|
\begin{itemize}
|
|
\item \texttt{if} \ldots \texttt{elif} \ldots \texttt{endif}
|
|
\end{itemize}
|
|
\item Les opérateurs de comparaisons:
|
|
\begin{itemize}
|
|
\item \texttt{<}
|
|
\item \texttt{>}
|
|
\item \texttt{==}
|
|
\item \texttt{in}
|
|
\item \texttt{not in}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
|
|
Regroupements avec le tag `{% regroup ... by ... as ... %}`.
|
|
* `{% url %}` pour construire facilement une URL à partir de son nom
|
|
* `urlize` qui permet de remplacer des URLs trouvées dans un champ de type CharField ou TextField par un lien cliquable.
|
|
* ...
|
|
|
|
Chacune de ces fonctions peut être utilisée autant au niveau des templates qu'au niveau du code.
|
|
Il suffit d'aller les chercher dans le package \texttt{django.template.defaultfilters}.
|
|
Par exemple:
|
|
|
|
\begin{minted}{python}
|
|
from django.db import models
|
|
from django.template.defaultfilters import urlize
|
|
|
|
|
|
class Suggestion(models.Model):
|
|
"""Représentation des suggestions.
|
|
"""
|
|
subject = models.TextField(verbose_name="Sujet")
|
|
|
|
def urlized_subject(self):
|
|
"""
|
|
Voir https://docs.djangoproject.com/fr/3.0/howto/custom-template-tags/
|
|
"""
|
|
return urlize(self.subject, autoescape=True)
|
|
\end{minted}
|
|
|
|
\subsubsection{Regroup by}
|
|
|
|
\subsubsection{Inclusion}
|
|
|
|
\subsection{Extensions non-natives}
|
|
|
|
En plus des quelques tags survolés ci-dessus, il est également possible de construire ses propres tags. La structure est un peu bizarre, car elle consiste à ajouter un paquet dans une de vos applications, à y définir un nouveau module et à y définir un ensemble de fonctions.
|
|
Chacune de ces fonctions correspondra à un tag appelable depuis vos templates.
|
|
|
|
Il existe trois types de tags *non-builtins*:
|
|
|
|
\begin{enumerate}
|
|
\item *Les filtres* - on peut les appeler grâce au *pipe* `|` directement après une valeur dans le template.
|
|
\item *Les tags simples* - ils peuvent prendre une valeur ou plusieurs en paramètre et retourne une nouvelle valeur. Pour les appeler, c'est *via* les tags \texttt{\{\% nom\_de\_la\_fonction param1 param2 \ldots \%\}}.
|
|
\item *Les tags d'inclusion*: ils retournent un contexte (ie. un dictionnaire), qui est ensuite passé à un nouveau template. Type \texttt{\{\% include '...' ... \%\}}.
|
|
\end{enumerate}
|
|
|
|
Pour l'implémentation:
|
|
|
|
1. On prend l'application `wish` et on y ajoute un répertoire `templatetags`, ainsi qu'un fichier `\_\_init\_\_.py`.
|
|
2. Dans ce nouveau paquet, on ajoute un nouveau module que l'on va appeler `tools.py`
|
|
3. Dans ce module, pour avoir un aperçu des possibilités, on va définir trois fonctions (une pour chaque type de tags possible).
|
|
|
|
\subsubsection{Filtres}
|
|
|
|
\begin{minted}{python}
|
|
# wish/tools.py
|
|
|
|
from django import template
|
|
|
|
from wish.models import Wishlist
|
|
|
|
register = template.Library()
|
|
|
|
@register.filter(is_safe=True)
|
|
def add_xx(value):
|
|
return '%sxx' % value
|
|
\end{minted}
|
|
|
|
\subsubsection{Tags simples}
|
|
|
|
Un \textbf{tag simple} reçoit une valeur ou un objet en entrée et génère une valeur de retour simple (un objet, un type natif, ...).
|
|
|
|
\begin{minted}{python}
|
|
# wish/tools.py
|
|
|
|
from django import template
|
|
|
|
from wish.models import Wishlist
|
|
|
|
|
|
register = template.Library()
|
|
|
|
|
|
@register.simple_tag
|
|
def current_time(format_string):
|
|
return datetime.datetime.now().strftime(format_string)
|
|
\end{minted}
|
|
|
|
\subsubsection{Tags d'inclusion}
|
|
|
|
Les \textit{tags d'inclusion} sont des tags associés à un (morceau de) template.
|
|
C'est-à-dire qu'une fois qu'ils auront réalisés le traitement qui leur est demandé, il généreront un canevas HTML qui sera \textbf{inclus} à l'endroit où le tag aura été appelé.
|
|
|
|
\begin{minted}{python}
|
|
# wish/tools.py
|
|
|
|
from django import template
|
|
|
|
from wish.models import Wishlist
|
|
|
|
|
|
register = template.Library()
|
|
|
|
|
|
@register.inclusion_tag('wish/templatetags/wishlists_list.html')
|
|
def wishlists_list():
|
|
return { 'list': Wishlist.objects.all() }
|
|
\end{minted}
|
|
|
|
\subsection{Pagination}
|
|
|
|
\section{Structure et configuration}
|
|
|
|
Il est conseillé que les templates respectent la structure de vos différentes applications, mais dans un répertoire à part.
|
|
Par convention, nous les placerons dans un répertoire \texttt{templates}.
|
|
La hiérarchie des fichiers devient alors celle-ci:
|
|
|
|
Par défaut, Django cherchera les templates dans les répertoirer d'installation.
|
|
Vous devrez vous éditer le fichier \texttt{gwift/settings.py} et ajouter, dans la variable \texttt{TEMPLATES}, la clé \texttt{DIRS} de la manière suivante:
|
|
|
|
\begin{minted}{python}
|
|
TEMPLATES = [
|
|
{
|
|
...
|
|
'DIRS': [ 'templates' ],
|
|
...
|
|
},
|
|
]
|
|
\end{minted}
|
|
|
|
\subsection{Fichiers statiques}
|
|
|
|
\section{Dynamisme - HTMX}
|
|
|
|
|