Including templates into LaTeX document
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Fred Pauchet 2022-05-03 22:10:58 +02:00
parent 6f868de04b
commit 5de564b21f
5 changed files with 125 additions and 110 deletions

View File

@ -2,7 +2,12 @@
Ou comment valider proprement des données entrantes.
\includegraphics{images/xkcd-327.png}
\begin{figure}[H]
\centering
\scalebox{1.0}{\includegraphics[max size={\textwidth}{\textheight}]{images/xkcd-327.png}}
\caption{XKCD 327}
\end{figure}
\begin{quote}
Le form, il s'assure que l'utilisateur n'a pas encodé de conneries et
@ -10,7 +15,7 @@ Ou comment valider proprement des données entrantes.
implémenté des closure tables dans un graph dirigé acyclique.
\end{quote}
Quand on parle de \texttt{forms}, on ne parle pas uniquement de formulaires Web.
Quand on parle de \texttt{forms}, on ne parle pas uniquement de formulaires Web.
On pourrait considérer qu'il s'agit de leur objectif principal, mais on peut également voir un peu plus loin: on peut en fait voir les \texttt{forms} comme le point d'entrée pour chaque donnée arrivant dans notre application: il s'agit en quelque sorte d'un ensemble de règles complémentaires à celles déjà présentes au niveau du modèle.
L'exemple le plus simple est un fichier \texttt{.csv}: la lecture de ce fichier pourrait se faire de manière très simple, en récupérant les valeurs de chaque colonne et en l'introduisant dans une instance du modèle.
@ -18,7 +23,7 @@ L'exemple le plus simple est un fichier \texttt{.csv}: la lecture de ce fichier
Mauvaise idée. On peut proposer trois versions d'un même code, de la version simple (lecture du fichier csv et jonglage avec les indices de colonnes), puis une version plus sophistiquée (et plus lisible, à base
de \href{https://docs.python.org/3/library/csv.html\#csv.DictReader}{DictReader}), et la version + à base de form.
Les données fournies par un utilisateur \textbf{doivent} \textbf{toujours} être validées avant introduction dans la base de données.
Les données fournies par un utilisateur \textbf{doivent} \textbf{toujours} être validées avant introduction dans la base de données.
Notre base de données étant accessible ici par l'ORM, la solution consiste à introduire une couche supplémentaire de validation.
Le flux à suivre est le suivant:
@ -52,7 +57,7 @@ A compléter ;-)
\section{Dépendance avec le modèle}
Un \textbf{form} peut hériter d'une autre classe Django.
Un \textbf{form} peut hériter d'une autre classe Django.
Pour cela, il suffit de fixer l'attribut \texttt{model} au niveau de la \texttt{class\ Meta} dans la définition.
\begin{minted}{python}
@ -67,7 +72,7 @@ Pour cela, il suffit de fixer l'attribut \texttt{model} au niveau de la \texttt{
fields = ('name', 'description')
\end{minted}
Notre form dépendra automatiquement des champs déjà déclarés dans la classe \texttt{Wishlist}.
Notre form dépendra automatiquement des champs déjà déclarés dans la classe \texttt{Wishlist}.
Cela suit le principe de \texttt{DRY\ \textless{}dont\ repeat\ yourself\textgreater{}\textasciigrave{}\_,\ et\ évite\ quune\ modification\ ne\ pourrisse\ le\ code:\ en\ testant\ les\ deux\ champs\ présent\ dans\ lattribut\ \textasciigrave{}fields},
nous pourrons nous assurer de faire évoluer le formulaire en fonction du
modèle sur lequel il se base.
@ -76,9 +81,9 @@ L'intérêt du form est de créer une isolation par rapport aux données provena
\section{Rendu et affichage}
Le formulaire permet également de contrôler le rendu qui sera appliqué lors de la génération de la page.
Le formulaire permet également de contrôler le rendu qui sera appliqué lors de la génération de la page.
Si les champs dépendent du modèle sur lequel se base le formulaire, ces widgets doivent être initialisés dans
l'attribut \texttt{Meta}.
l'attribut \texttt{Meta}.
Sinon, ils peuvent l'être directement au niveau du champ.
\subsection{Squelette par défaut}
@ -87,13 +92,13 @@ On a d'un côté le \{\{ form.as\_p \}\} ou \{\{ form.as\_table \}\}, mais il y
\subsection{Crispy-forms}
Comme on l'a vu à l'instant, les forms, en Django, c'est le bien.
Comme on l'a vu à l'instant, les forms, en Django, c'est le bien.
Cela permet de valider des données reçues en entrée et d'afficher (très) facilement des formulaires à compléter par l'utilisateur.
Par contre, c'est lourd.
Par contre, c'est lourd.
Dès qu'on souhaite peaufiner un peu l'affichage, contrôler parfaitement ce que l'utilisateur doit remplir,
modifier les types de contrôleurs, les placer au pixel près, ...
Tout ça demande énormément de temps.
modifier les types de contrôleurs, les placer au pixel près, ...
Tout ça demande énormément de temps.
Et c'est là qu'intervient \href{http://django-crispy-forms.readthedocs.io/en/latest/}{Django-Crispy-Forms}.
Cette librairie intègre plusieurs frameworks CSS (Bootstrap, Foundation et uni-form) et permet de contrôler entièrement le \textbf{layout} et la présentation.

101
chapters/templates.tex Normal file
View File

@ -0,0 +1,101 @@
\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 \}\}}, ... 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 et extensions}
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{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:

View File

@ -47,9 +47,11 @@
d'hébergement de fichiers, quels qu'ils soient. Il peut s'agir de
fichiers de logs, de données applications, de fichiers média envoyés par
vos utilisateurs, de vidéos et images ou de données de sauvegardes.
\textbf{\url{https://aws.amazon.com/fr/s3/}.}
\includegraphics{images/amazon-s3-arch.png}
\end{description}
\textbf{\url{https://aws.amazon.com/fr/s3/}.}
\includegraphics{images/amazon-s3-arch.png}

View File

@ -71,6 +71,7 @@
\include{chapters/administration.tex}
\include{chapters/urls.tex}
\include{chapters/forms.tex}
\include{chapters/templates.tex}
\include{chapters/authentication.tex}
\include{chapters/context-processors.tex}
\chapter{Conclusions}

View File

@ -1,104 +1,10 @@
== 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 *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.
En intégrant un ensemble de *tags*, cela vous permettra de greffer les données reçues en entrée dans un patron prédéfini.
NOTE: (je ne sais plus ce que je voulais dire ici)
Un squelette de page HTML basique ressemble à ceci:
[source,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>
----
Notre première vue permettra de récupérer la liste des objets de type `Wishlist` que nous avons définis dans le fichier `wish/models.py`. Supposez que cette liste soit accessible *via* la clé `wishlists` d'un dictionnaire passé au template. Elle devient dès lors accessible grâce aux tags `{% for wishlist in wishlists %}`. A chaque tour de boucle, on pourra directement accéder à la variable `{{ wishlist }}`. De même, il sera possible d'accéder aux propriétés de cette objet de la même manière: `{{ wishlist.id }}`, `{{ wishlist.description }}`, ... et d'ainsi respecter la mise en page que nous souhaitons.
En reprenant l'exemple de la page HTML définie ci-dessus, on pourra l'agrémenter de la manière suivante:
[source,django]
----
<!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>
----
image::images/html/my-first-wishlists.png[]
Mais plutôt que de réécrire à chaque fois le même entête, on peut se 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'*é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:
[source,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>
----
<1> Un bloc `title`
<2> Un bloc `body`
La page HTML pour nos listes de souhaits devient alors:
[source,html]
----
<!-- templates/wishlist/wishlist_list.html -->
{% extends "base.html" %} <1>
{% block title %}{{ block.super }} - Listes de souhaits{% endblock %} <2>
{% block body %} <3>
<p>Mes listes de souhaits</p>
<ul>
{% for wishlist in wishlists %}
<li>{{ wishlist.name }}: {{ wishlist.description }}</li>
{% endfor %}
</ul>
----
<1> On étend/hérite de notre page `base.html`
<2> On redéfinit le titre (mais on réutilise le titre initial en appelant `block.super`)
<3> On définit uniquement le contenu, qui sera placé dans le bloc `body`.
=== Structure et configuration
==== Répertoires de découverte des templates
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 `templates`. La hiérarchie des fichiers devient alors celle-ci:
[source,bash]
----
$ tree templates/