Alors que Django célèbre ses 20 ans cette année, la version 6.0 vient tout juste de sortir (3 décembre 2025). Cette version introduit des outils que la communauté attendait avec impatience. Nous allons passer en revue quelques-unes de ces fonctionnalités.
Sécurité et Frontend
Pour commencer, il est important de noter que Django 6.0 supporte les versions de Python 3.12, 3.13, et 3.14.
Content Security Policy (CSP) native
Pour ceux qui ne connaissent pas la CSP, il faut le voir comme un agent de sécurité a l'entrée de votre application web. Il laisse entrer vos images, scripts, styles, mais si un script malveillant essaye d'entrer via une faille XSS, la CSP le bloque.
Jusqu'à maintenant, pour implémenter la CSP, il fallait utiliser django-csp. Mais Django 6.0 intègre un middleware dédié pour gérer cette liste blanche nativement.
**Exemple tiré de la release note : **
Les réglages acceptent des dictionnaires Python et des constantes fournies par Django.
from django.utils.csp import CSP
SECURE_CSP = {
"default-src": [CSP.SELF], # Par défaut : uniquement mon domaine
"script-src": [CSP.SELF, CSP.NONCE], # JS : mon domaine + nonce pour inline
"img-src": [CSP.SELF, "https:"], # Images : mon domaine + tout HTTPS
}
L'en-tête Content-Security-Policy résultant ressemblera à ceci :
default-src 'self'; script-src 'self' 'nonce-SECRET'; img-src 'self' https:
À noter
XSS (Cross-Site Scripting) : C'est lorsqu'un attaquant réussit à injecter du code JavaScript malveillant dans votre site (par exemple via un formulaire mal sécurisé). Ce script peut alors voler les cookies de vos utilisateurs, rediriger vers des sites frauduleux, etc.
L'en-tête CSP : C'est une instruction que votre serveur Django envoie au navigateur lui demandant de : « n'exécuter que les scripts/images/styles que j'autorise explicitement. » Le navigateur obéit et bloque tout le reste.
Les templates partials
Et si nous commencions cette partie par une démonstration ? 😁
Les Template Partials permettent de définir des fragments de HTML réutilisables directement à l'intérieur de fichiers de template, ce qui permet de ne plus avoir besoin de créer de multiples petits fichiers pour chaque composant. Comme vous pouvez le voir dans la vidéo ci-dessous, cette architecture orientée composants simplifie les interactions dynamiques comme avec HTMX.
Définir un Partial
<!--index.html--> {% partialdef card %} <article> <header> <h3>{{ post.title }}</h3> </header> <!-- Contenu... --> </article> {% endpartialdef %}
À noter
Par défaut, partialdef ne fait que définir le bloc sans l'afficher. Il faut l'appeler explicitement pour l'afficher.
Réutilisation du partial
Le partial peut être utilisé dans le même template :
<!--index.html-->
{% for post in posts %}
{# Affiche le partial 'card' pour chaque itération #}
{% partial card %}
{% endfor %}
Ou dans un autre template :
<!--Autre fichier que index.html : par exemple home.html-->
{% include "index.html#card" %}
Pour l'utiliser, prenons un exemple complet avec deux vues et un fichier index.html.
- Le fichier
index.html
{% extends "blog/base.html" %}
{% block content %}
<h2>Liste des articles</h2>
{# 1. DÉFINITION DU PARTIAL #}
{# On définit le bloc réutilisable ici. #}
{% partialdef card %}
<article>
<header>
<h3>{{ post.title }}</h3>
</header>
<p>{{ post.content }}</p>
<footer>
<a href="{% url 'post_partial' post.pk %}" target="_blank">Lien classique</a>
<button
hx-get="{% url 'post_partial' post.pk %}"
hx-target="#preview-area"
hx-swap="innerHTML">
Charger (HTMX)
</button>
</footer>
</article>
{% endpartialdef %}
{# 2. ZONE D'APERÇU #}
<section>
<h3>Zone d'aperçu HTMX</h3>
<div id="preview-area">
<p><em>Le contenu chargé apparaîtra ici...</em></p>
</div>
</section>
<hr>
{# 3. LISTE #}
<section>
<h3>Liste des articles</h3>
{% for post in posts %}
{% partial card %}
{% empty %}
<p>Aucun article. Ajoutez-en via l'admin !</p>
{% endfor %}
</section>
{% endblock %}
- Le fichier
views.py
# Imaginons un modèle Post existant from django.shortcuts import render, get_object_or_404 from .models import Post def index(request): posts = Post.objects.all() return render(request, "blog/index.html", {"posts": posts}) def single_post_partial(request, pk): post = get_object_or_404(Post, pk=pk) # C'est ici que la magie opère : on cible le partial avec #card return render(request, "blog/index.html#card", {"post": post})
Vous pouvez retrouver un exemple complet via ce lien : https://github.com/gabigab117/django6.0-partials.
Déclarer et utiliser un partial en même temps
Il est tout à fait possible à la fois de déclarer et d'utiliser un partial. Voici un exemple très parlant tiré de la documentation de Django :
{# Define and render immediately. #}
{% partialdef user-info inline %}
<div id="user-info-{{ user.username }}">
<h3>{{ user.name }}</h3>
<p>{{ user.bio }}</p>
</div>
{% endpartialdef %}
{# Other page content here. #}
{# Reuse later elsewhere in the template. #}
<section class="featured-authors">
<h2>Featured Authors</h2>
{% for user in featured %}
{% partial user-info %}
{% endfor %}
</section>
Le framework de Tâches (Tasks)
Django 6.0 propose une abstraction intégrée pour définir et envoyer des tâches. Avant cette nouveauté, nous avions l'habitude d'utiliser un outil comme Celery.
Attention
Django fournit l'interface et le mécanisme de file d'attente, mais pas (encore) le worker de production pour l'exécution des tâches.
Définir une tâche
Pour définir une tâche, il faut utiliser le décorateur @task :
from django.tasks import task from django.core.mail import send_mail @task def send_welcome_email(user_email): """ Cette fonction sera exécutée en arrière-plan. """ send_mail( subject="Bienvenue !", message="Merci de vous être inscrit sur notre plateforme.", from_email="[email protected]", recipient_list=[user_email], )
Mise en file d'attente de la tâche
Il faut mettre cette tâche dans une file d'attente :
from .tasks import send_welcome_email def register_view(request): # ... logique d'inscription ... # Au lieu de bloquer la requête, on délègue : send_welcome_email.enqueue(user_email=user.email) return redirect('success')
Pour le développement local, Django 6.0 inclut des backends simples qui ne nécessitent pas d'infrastructure particulière. Par défaut, Django 6.0 utilise le ImmediateBackend (je vous invite à consulter cette partie de la documentation).
Pour la production, il faudra utiliser une bibliothèque tierce comme django-tasks qui stocke les tâches en base de données. Peut-être que ça sera un jour intégré à Django ? 😁
Quelques autres améliorations
Nous retrouvons plusieurs autres améliorations avec cette version 6.0, telles que l'API Email de Django qui utilise maintenant l'API moderne email.message.EmailMessage de Python 3.6+. Ce qui implique entre autres une meilleure gestion de l'Unicode. Il y a aussi plusieurs nouveaux imports avec la commande python manage.py shell, des optimisations au niveau de l'ORM, et bien plus encore !
Je vous invite à lire la release note de Django 6.0 pour voir la liste complète des changements.