Les nouveautés de Django 6.0

Tâches d'arrière-plan natives, sécurité CSP et templates partiels, voici quelques nouveautés de Django 6.0

Publié le par Gabriel Trouvé (mis à jour le )
20 minutes

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 %}
HTML

À 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 %}
HTML

Ou dans un autre template :

<!--Autre fichier que index.html : par exemple home.html-->
{% include "index.html#card" %}
HTML

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 %}
HTML
  • 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})
PYTHON

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>
HTML

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],
    )
PYTHON

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')
PYTHON

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.

Bravo, tu es prêt à passer à la suite

Rechercher sur le site

Formulaire de contact

Inscris-toi à Docstring

Pour commencer ton apprentissage.

Tu as déjà un compte ? Connecte-toi.