---
title: Django
author: Steve Kossouho
---

# Templates avec Django

:::notes
Préférer commencer par les vues, pour avoir des vues où utiliser des templates...
:::

----

## Principe de templating

Le concept de [templating]{.naming} (gabarits en français) consiste à utiliser des fichiers contenant du texte
avec des emplacements réservés, qui seront remplis à la demande pour afficher des données personnalisées à l'utilisateur 
(par exemple, le système permet de générer un email de bienvenue commençant par « Bonjour `votre prénom` »).

Ce concept est fourni par de nombreuses bibliothèques, et ce dans plusieurs langages (PHP, Javascript, C++, Python etc.)

----

### Exemples de systèmes de templating en Python

Il existe un certain nombre de moteurs de templating assez populaires en Python :

- [Django](https://docs.djangoproject.com/en/3.2/topics/templates/) : Intégré à Django, propose un bon compromis entre performance et sécurité. 
- [Jinja 3](https://jinja.palletsprojects.com/en/3.0.x/) : Basé sur Django (et Genshi ?), mais utilisable dans tout projet Python. *Instagram*
- [Mako](https://www.makotemplates.org/) : Performant, autorise le code Python brut. *Reddit*
- [Genshi](https://genshi.readthedocs.io/en/latest/) : Utilisé dans TurboGears

Django est à l'origine de deux moteurs de templates populaires, tels que `Jinja` pour Python et `Twig` pour PHP qui en reprennent largement la syntaxe.

----

## Principe de templating dans Django

Un moteur de templates propose une façon simple et rapide de générer du contenu en rédigeant
des gabarits (des squelettes de document), des modèles où il ne reste plus qu'à renseigner des éléments manquants. 
Il existe plusieurs façons de procéder lorsqu'on conçoit un langage de templates :

- Un moteur peut offrir la possibilité d'insérer des expressions Python sans limite dans un document de template
- Un langage peut permettre d'écrire du Python brut pour générer du contenu
- Un langage peut offrir des fonctionnalités limitées pour éviter des injections de code ou l'écriture de code métier en dehors du code principal

----

Les considérations suivantes ont mené à la création du moteur de templates de Django :

- Les templates sont souvent rédigés et modifiés par des designers (HTML notamment)
- Écrire du code Python ne devrait se faire que dans des fichiers Python
- Exécuter du code Python en dehors de scripts Python normaux rend un programme plus dur à déboguer
- Un designer ou intégrateur ne devrait pas être tenu d'apprendre le Python

----

Ainsi, le moteur de templates de Django repose sur des paradigmes simples :

- Une syntaxe peu variée pour simplifier l'apprentissage (interpolation, attributs, filtres et balises)
- Pas une ligne de Python autorisée (même si la syntaxe est similaire)
- Système extensible, mais uniquement via du code Python

----

## Le langage de templates de Django

Toute la section qui va suivre concerne les éléments de langage spécifiques aux templates de Django.

----

### Créer des templates

Par défaut, Django ne sait trouver et exploiter des documents de templates que grâce à un paramètre `TEMPLATES` dans le fichier `settings` de votre projet :

```python {.numberLines}
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],  # Répertoires où trouver des templates
        "APP_DIRS": True,  # Utiliser le répertoire `templates` de mes applications
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
            ],
        },
    },
]
```

----

- [Documentation sur le paramètre `TEMPLATES`](https://docs.djangoproject.com/en/dev/ref/settings/#templates)
- La clé `BACKEND` permet de choisir le moteur de templates de Django (parmi deux)
- La clé `APP_DIRS` permet d'indiquer si les répertoires `templates` des applications tierces sont automatiquement utilisés par le moteur.
- La clé `DIRS`, elle, permet de spécifier des répertoires supplémentaires dans lesquels le moteur de templates de Django ira automatiquement chercher des fichiers de templates.

----

### Nommage des templates

Dans Django, lorsque vous souhaitez afficher un template au navigateur, vous avez accès à une fonction de raccourci nommée `django.shortcuts.render(request, template, context)`.

Si vous appelez cette fonction avec les arguments `render(request, "index.html", {"value": 3.14159})`{.py} :

- Django va considérer le premier fichier `index.html` trouvé dans les répertoires `templates` des applications tierces (celles indiquées dans `settings.INSTALLED_APPS`)
- Le fichier `index.html` sera rendu en ayant accès aux données de `context`
- La fonction renverra à la fin un objet `HttpResponse` avec le document rendu.
- [Documentation sur la fonction `render`](https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render)

----

#### Exemple de template

```python {.numberLines}
from django.shortcuts import render

def index(request):
    return render(request, "index.html", {"value": 3.14159})
```

Le template `index.html` peut être trouvé dans le dossier `templates` de votre application :

```html {.numberLines}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Index</title>
</head>
<body>
    <h1>Index</h1>
    <p>Value: {{ value }}</p>
</body>
</html>
```

----

### Commentaires

En HTML, la balise de commentaire s'écrit de la façon suivante :

```html {.numberLines}
<!-- Texte de commentaire HTML -->
```

C'est utile pour annoter un document, mais deux choses se produisent :

- Le commentaire est visible dans le navigateur.
- Écrire ce type de commentaire dans un document qui n'est pas du HTML ne fonctionnera pas.

Avec Django, on peut insérer un vrai commentaire de template via la balise suivante :

```djangotemplate {.numberLines}
{# Texte de commentaire Django #}
```

Le commentaire ne sera jamais rendu par le moteur, au même titre que les commentaires Python sont ignorés par l'interpréteur. Essayez autant que possible de vous en servir pour plus facilement relire vos templates _a posteriori_.

----

### Interpolation de données

Lorsque vous effectuez le rendu d'un template, le seul moyen d'y insérer des données est de les passer via un [contexte]{.naming}. Un contexte est un simple **dictionnaire Python**, où les clés sont des noms qui seront utilisables uniquement dans le template. Si en Python, on rend un template :

```python {.numberLines}
from django.shortcuts import render

def view_func(request):
    return render(request, "template.html", {"name": "Maurice"})
```

Le template aura uniquement accès à une donnée nommée `name` et dont la valeur sera `"Maurice"`{.py}. (Voir [Documentation sur les modifieurs de contexte](https://docs.djangoproject.com/en/dev/ref/templates/api/#built-in-template-context-processors) pour savoir quels autres noms sont rendus disponibles dans le contexte de template)

```djangotemplate {.numberLines}
Bonjour, {{ name }}
```

----

#### Interpoler un attribut d'une variable

Lorsqu'une des variables du contexte est un objet qui contient des attributs, vous pouvez les interpoler avec la syntaxe suivante :

```djangotemplate {.numberLines}
{{ var1.attribute }}
```

----

#### Interpoler un élément d'une variable (clé ou index)

De la même façon, si votre variable de contexte est une **liste** ou un **dictionnaire** dont vous voulez récupérer un élement, et que vous connaissez son index ou bien sa clé, vous pouvez utiliser la syntaxe suivante :

```djangotemplate {.numberLines}
{{ var1.nom_de_la_clé }} {# clé de dictionnaire qui est une chaîne #}
{{ var2.numéro_d'index }} {# index de séquence #}
```

----

#### Interpoler la valeur de retour d'une méthode

Pour terminer, si votre variable de contexte est un objet dont vous voulez récupérer la valeur de retour d'une méthode, vous pouvez écrire :

```djangotemplate
{{ var1.nom_de_la_methode }}
```

Cette méthode sera **toujours** appelée sans argument.

----

#### Interpolation et limitations

Le langage de templates de Django a des restrictions sur les interpolations :

- Vous ne pouvez pas passer d'arguments lorsque vous appelez une méthode et c'est intentionnel, seules les méthodes acceptant uniquement des arguments facultatifs sont utilisables.
- Vous ne pouvez pas utiliser d'attributs ou méthodes commençant par `_`{.py} (considérées comme privées en Python).

----

### Filtres de templates

Lorsque vous effectuez une interpolation dans un template (`{{ ... }}`), vous avez la possibilité de transformer l'interpolation, souvent pour des questions de présentation. Pour effectuer ce genre de traitement sur une interpolation, vous devez utiliser des [filtres]{.naming}.

Les filtres permettent de transformer une interpolation et fonctionnent sur chaînes, dates, listes et d'autres types. (voir [filtres intégrés à Django](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#built-in-filter-reference))

----

#### Filtre basique (sans argument)

Un filtre s'utilise simplement en le "pipant" à l'expression à transformer. Le résultat affiché sera celui du filtre.
Il est possible d'utiliser plusieurs filtres successivement en les chaînant.

```djangotemplate {.numberLines}
{# Utilisation du filtre upper, pour mettre en majuscules #}
<h1>{{ name|upper }}</h1>
```

----

#### Filtre avec argument

Certains filtres acceptent un argument (**et un seul maximum**). Pour les utiliser, il suffit de faire suivre le nom du filtre par `:` et d'indiquer à la suite la valeur du paramètre, généralement sous forme d'une chaîne de caractères. Ceci est documenté pour chaque filtre disponible.

```djangotemplate {.numberLines}
{# Utilisation du filtre date pour formater un objet datetime #}
<p>Date de création : {{ moment|date:"d m Y" }}</p>
```

----

#### Filtres fréquents

Parmi les nombreux [filtres disponibles de base dans Django](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#built-in-filter-reference), certains seront plus souvent utilisés que d'autres, comme par exemple :

| Filtre                                     | Description                                                                                        |
|--------------------------------------------|----------------------------------------------------------------------------------------------------|
| `upper` et `lower`                         | Pour changer la casse du texte (majuscules et minuscules).                                         |
| `default:value`                            | Si la valeur équivaut à `False`, utiliser `value` par défaut.                                      |
| `default_if_none:value`                    | Si la valeur équivaut à `None`, utiliser `value` par défaut.                                       |
| `date:format`                              | Interpoler un objet `datetime` avec un format spécifique.                                          |
| `length`                                   | Interpoler la longueur d'une collection.                                                           |
| `safe`                                     | Ne pas échapper le contenu à interpoler. Permet d'insérer du HTML.                                 |
| `truncatechars:num` et `truncatewords:num` | Couper et placer une ellipse (tronquer le texte après un certain nombre de caractères ou de mots). |


----

### Balises de templates

Nous venons de voir que l'on pouvait "filtrer" du contenu provenant d'une interpolation. Et s'il était possible d'utiliser des
outils plus avancés, permettant de générer des données dynamiques, ou même de rendre du contenu conditionnel, par exemple ?

Le moteur de templates de Django fournit un système de [balises]{.naming} qui nous permet d'accéder à des comportements plus avancés. 
Grâce aux balises, nous allons pouvoir utiliser des boucles, conditionner le rendu d'un segment de template, configurer le rendu par le
moteur ou encore modifier le contexte de rendu...

----

### Syntaxe des balises

Pour utiliser des balises de gabarit, le plus important, c'est d'en connaitre la syntaxe. Pour utiliser une balise, il faut écrire :

```djangotemplate {.numberLines}
{% tag_name argument1 argument2... %}
```

Entre les marqueurs `{% ... %}` il suffit d'indiquer le nom de la balise et d'y ajouter, séparés par des espaces, autant d'arguments que ce qu'accepte la balise. Certaines balises fonctionnent par paire, comme `{% if %}…{% endif %}`{.djangotemplate}, ou  `{% for %}…{% endfor %}`{.djangotemplate}. Ces balises sont documentées dans la [documentation officielle de Django](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#built-in-tag-reference)

----

### Balises natives

Pour aborder le chapitre des balises, nous allons nous intéresser à certaines balises précises dédiées à des outils importants.

----

#### Conditions

| Balise        | Description                                                                               |
|---------------|-------------------------------------------------------------------------------------------|
| `{% if %}`    | Évalue une condition et affiche le contenu si la condition est vraie.                     |
| `{% elif %}`  | Alternative à `{% if %}` si la première condition est fausse.                             |
| `{% else %}`  | Définit un bloc à afficher si aucune des conditions précédentes n'est vraie.              |
| `{% endif %}` | Termine une instruction conditionnelle.                                                   |

----

#### Boucles

| Balise                 | Description                                                                               |
|------------------------|-------------------------------------------------------------------------------------------|
| `{% for ... in ... %}` | Itère sur une séquence d'objets.                                                          |
| `{% empty %}`          | Définit un bloc à afficher si la séquence est vide.                                       |
| `{% endfor %}`         | Termine une boucle.                                                                       |

----

#### Autres Balises Importantes

| Balise                                | Description                                                    |
|---------------------------------------|----------------------------------------------------------------|
| `{% include %}`                       | Inclut un autre template.                                      |
| `{% extends %}`                       | Indique que le template hérite d'un autre template.            |
| `{% block %}`                         | Définit un bloc de contenu modifiable dans un template hérité. |
| `{% endblock %}`                      | Termine un bloc de contenu.                                    |
| `{% url %}`                           | Génère une URL vers une vue nommée.                            |
| `{% csrf_token %}`                    | Génère un jeton CSRF pour sécuriser les formulaires.           |
| `{% comment %}` et `{% endcomment %}` | Commente une section du template.                              |
| `{% load %}`                          | Charge une bibliothèque de tags personnalisés.                 |
| `{% with %}` et `{% endwith %}`       | Assigne une ou plusieurs variables pour une portée limitée.    |
| `{% endwith %}`                       | Termine le bloc `with`.                                        |

----

| Balise                | Description                                                                          |
|-----------------------|--------------------------------------------------------------------------------------|
| `{% autoescape %}`    | Active ou désactive l'échappement automatique dans un bloc.                          |
| `{% endautoescape %}` | Termine le bloc `autoescape`.                                                        |
| `{% now %}`           | Affiche la date et l'heure actuelles selon un format spécifié.                      |
| `{% spaceless %}`     | Supprime les espaces blancs entre les balises HTML dans le contenu du bloc.          |
| `{% endspaceless %}`  | Termine le bloc `spaceless`.                                                         |
| `{% verbatim %}`      | Ignore le rendu des balises Django dans le contenu du bloc.                          |
| `{% endverbatim %}`   | Termine le bloc `verbatim`.                                                          |

----

### Structures de contrôle : `if`

Vous pouvez grace aux balises `{% if %}`{.djangotemplate} et `{% else %}`{.djangotemplate} construire un document dont certaines zones seront rendues conditionnellement.
La syntaxe de la balise est similitaire aux structures conditionnelles en Python.

```djangotemplate {.numberLines}
{% if expression %}
    Contenu si la condition est vraie
{% elif expression %}
    Contenu si la premiere condition est fausse
{% else %}
    Contenu si la condition est fausse
{% endif %}
```

----

### Structures de contrôle : `for`

Si vous souhaitez générer du contenu pour chaque élément d'un itérable, vous pouvez utiliser la balise `{% for %}`{.djangotemplate}. La syntaxe 
de la balise est similaire aux structures de boucle en Python, à l'exception de l'existence d'une clause `{% empty %}`{.djangotemplate}, 
dont le contenu sera affiché si l'itérable est vide.

```djangotemplate {.numberLines}
{% for name in iterable %}
    Contenu de l'itération {{ name }}
{% empty %}
    Contenu si la boucle est vide
{% endfor %}
```

----

### Inclusion de templates

La balise `{% include %}`{.djangotemplate} permet d'inclure un autre template dans le template actuel. L'intérêt d'inclure des templates est de pouvoir les utiliser comme **composants** dans certains cas répétitifs. Il est possible de transmettre un contexte spécifique lors de l'inclusion de templates.

```djangotemplate {.numberLines}
{% for user in users %}
    {% include "path/to/user_template.html" with user=user %}
{% endfor %}
```

```djangotemplate {.numberLines}
<card>
    <img src="{{ user.picture.url }}">
    <p>{{ user.username }}</p>
</card>
```

----

### Héritage de templates

Dans un site web, beaucoup de pages partagent la même structure. Par exemple, sur de nombreux sites, la barre de navigation est identique et le pied de page également. Il semblerait redondant de devoir répéter dans les templates de diverses sections le même code HTML, notamment l'en-tête HTML ou le pied de page.

Django propose un système d'héritage de templates, permettant de partager des blocs de contenu entre plusieurs templates. La fonctionnalité est offerte via deux balises, `{% block %}`{.djangotemplate} et `{% extends %}`{.djangotemplate}.

----

Dans l'héritage de templates, vous avez deux notions de base :

1. Un [template de base]{.naming} ou template parent. Ce template est le template principal du site, et permet de fournir le contenu commun aux autres templates.
2. Un [template enfant]{.naming}. Ce template est le template qui hérite du template de base, et qui ajoute ou modifie du contenu via des [blocs]{.naming}.

----

#### Template de base

```djangotemplate {.numberLines}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        {# Contenu commun aux templates enfants #}
        {% block body %}{% endblock body %}
    </body>
</html>
```

Un template de base propose un contenu fixe qui servira de base aux templates enfants. Ce même template proposera des duos de balises `{% block name %}`{.djangotemplate} et `{% endblock name %}`{.djangotemplate}, dont le contenu sera personnalisable par les templates enfants.

----

Dans un [template de base]{.naming}, qui contient un document HTML classique, on a tendance à décrire des blocs personnalisables (via la balise `{% block %}`{.djangotemplate}) pour des sections du document qui sont souvent les mêmes, en voici une liste :

- Le titre de la page (`<head><title>`) est souvent l'objet d'un bloc Django, nommé `title` ou `page_title`
- Si la page contient un titre ous forme de balise `<h1>`, son contenu peut faire l'objet d'un bloc Django, nommé `title`
- Dans la balise HTML `<head>`, on crée souvent un bloc Django destiné à ajouter des fichiers CSS, souvent nommé `css`
- Dans la balise HTML `<head>`, on crée souvent un bloc Django destiné à ajouter des fichiers JavaScript, souvent nommé `js`

----

#### Template enfant

```djangotemplate {.numberLines}
{% extends "path/to/base_template.html" %}
{% block body %}
    Contenu de remplacement du block body, spécifique au template enfant
{% endblock body %}
```

Un template enfant hérite via la balise `{% extends %}`{.djangotemplate} de Django. Il peut ensuite uniquement modifier le contenu des blocs `{% block %}`{.djangotemplate} et `{% endblock %}`{.djangotemplate} de son template de base. Tout le reste du contenu du template enfant sera ignoré.

----

#### Réutiliser des blocs dans un template enfant

Dans un template enfant, lorsque vous personnalisez un bloc avec la balise `{% block %}`{.djangotemplate}, vous avez la possibilité de récupérer 
le contenu original du bloc provenant du template parent, grâce à une variable de contexte nommée `block.super`{.djangotemplate}.

```djangotemplate {.numberLines}
{% extends "path/to/base_template.html" %}
{% block body %}
    {{ block.super }}
    Contenu ajouté au block body, spécifique au template enfant
{% endblock body %}
```

----

#### Stratégies de création des templates

En général, lorsque l'on souhaite exploiter les fonctionnalités d'héritage de templates, on essaie d'organiser l'arborescence des templates
de façon à faciliter leur maintenance. Quelques astuces à ce sujet :

- Le **template de base** peut se trouver à la racine d'un dossier de templates personnalisé (voir la clé `["DIRS"]`{.python} de `settings.TEMPLATES`)
- Le **template de base** peut aussi se trouver à la racine du répertoire `templates` de l'application Django principale.
- Les autres templates se trouvent généralement dans un sous-dossier de `templates` portant le nom de l'application Django. 
- Les autres templates peuvent être de plusieurs types :
  - Template pour une page entière
  - Template utilisé avec la balise Django `{% include %}`{.djangotemplate}
  - Template pour générer le contenu d'e-mails
  - etc.
- Tous ces templates peuvent être organisés dans des répertoires séparés indiquant leur usage.

----

![Exemple d'organisation de répertoire de templates](assets/images/templating-folder-example.png)

----

## Balises utiles

Parmi les balises disponibles par défaut dans Django, quelques autres sont indispensables :

| Balise                                                            | Description                                     |
|-------------------------------------------------------------------|-------------------------------------------------|
| `{% url %}`{.djangotemplate}                                      | Rendre une URL que l'on a nommée                |
| `{% with %}`{.djangotemplate} et `{% endwith %}`{.djangotemplate} | Créer un contexte temporaire                    |
| `{% load %}`{.djangotemplate}                                     | Chargement de tags et filtres                   |
| `{% csrf_token %}`{.djangotemplate}                               | Insérer un champ de sécurité dans un formulaire |

----

### `{% url %}`{.djangotemplate}

La balise `{% url %}`{.djangotemplate} permet de rendre une URL que l'on a nommée. Si nous avons défini l'URL suivante :

```python {.numberLines}
from django.urls import path

urlpatterns = [
    path("url/path/<type:param>", view_name, name="named"),
]
```

Nous pouvons insérer dans un template l'URL fixe, quelle qu'elle soit, en utilisant la balise `{% url %}`{.djangotemplate} comme suit.
Si l'URL exacte nécessite une valeur spécifique d'un argument ou de plusieurs arguments, nous pouvons utiliser la syntaxe suivante :

```djangotemplate
<a href="{% url "named" param=value%}">Anchor text</a>
```

----

### `{% with %}`{.djangotemplate}

Lorsque certaines expressions complexes sont nécessaires à plusieurs endroits dans un template, ex. :

```djangotemplate {.numberLines}
{{ variable.method|filter1|filter2 }}
...
{{ variable.method|filter1|filter2 }}
```

On peut utiliser la balise `{% with %}`{.djangotemplate} pour créer des variables de contexte temporaires.
Cela permet d'utiliser un nom de variable simple pour référencer cette expression si longue à rédiger.

```djangotemplate {.numberLines}
{% with name=variable.method|filter1|filter2 %}
    {{ name }}
    ...
    {{ name }}
{% endwith %}
```

----

### `{% load %}`{.djangotemplate}

Dans les templates de Django, la balise `{% load %}`{.djangotemplate} permet de charger des tags et des filtres personnalisés.
Par défaut, seuls les tags et filtres fournis par Django sont chargés. Lorsqu'une application fournit ses propres tags et filtres, il est possible de les charger via la balise `{% load %}`{.djangotemplate}, d'une manière similaire aux importations de modules Python.

```djangotemplate {.numberLines}
{% load mytags %}
{% load myfilters %}
```

La balise sera généralement nécessaire lors de l'usage de fichiers statiques (ex. CSS et JavaScript).

```djangotemplate {.numberLines}
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
```

----

## Balises et filtres personnalisés

Django permet de développer ses propres filtres et tags, qui pourront être utilisables dans nos 
templates. Une fois créés, nous pouvons les importer dans un template via la balise `{% load %}`{.djangotemplate}.

Voir la [documentation officielle sur les filtres personnalisés](https://docs.djangoproject.com/fr/3.2/howto/custom-template-tags/#custom-template-tags-and-filters)

:::notes
Faire la démo de l'écriture d'un filtre notamment et d'une balise simple, puis proposer un exercice.
:::

----

## Fichiers statiques

[Documentation de la gestion des fichiers statiques](https://docs.djangoproject.com/en/dev/howto/static-files/)

Lorsque l'on sert du HTML, le document référence souvent des fichiers statiques tels que des feuilles de style CSS, des fichiers de code JavaScript ou encore des images spécifiques au site (bannière, logo, tout média qui n'est pas envoyé dynamiquement par les utilisateurs du site). 

Django simplifie l'utilisation de ces fichiers pour le développement, et offre également des commandes de gestion (`manage.py`) pour préparer
le passage en production.

----

Il y a plusieurs étapes à suivre lorsque l'on souhaite utiliser des fichiers statiques en développement :

1. Vérifier que `"django.contrib.staticfiles"` est présent `settings.INSTALLED_APPS`
2. Avoir un répertoire `static/` dans une ou plusieurs applications (ou créer un répertoire personnalisé)
3. Ajouter dans `settings.py` une liste dans `STATICFILES_DIRS` qui contient les répertoires `static` que vous avez créés
4. Ajouter `{% load static %}`{.djangotemplate} aux templates utilisant la balise `{% static %}`{.djangotemplate}
5. Référencer le chemin relatif de la ressource via `{% static "chemin/relatif.ext" %}`

À l'exécution, et uniquement en mode `DEBUG = True`{.python}, le serveur de développement de Django sera capable 
de trouver et servir correctement les ressources stockées dans les répertoires `static` au navigateur.

----

![Utilisation de la balise static](assets/images/templating-tags-static.png)

