Vue d'ensemble
Django 3.1, publié le 4 août 2020, poursuit la transition vers l'asynchrone initiée par Django 3.0. Les vues, les middlewares et les tests supportent désormais nativement async/await. L'autre nouveauté marquante est JSONField, disponible pour toutes les bases de données supportées, et non plus seulement PostgreSQL. Cette version ajoute également le support de pathlib.Path dans les réglages.
Fonctionnalités principales
JSONField pour toutes les bases de données
Le champ JSONField du module django.db.models fonctionne désormais avec SQLite, MySQL, MariaDB et PostgreSQL. Jusqu'ici, seul django.contrib.postgres.fields.JSONField était disponible. Le nouveau champ universel prend en charge les lookups comme __contains, __has_key et les chemins avec des transformations clé/index.
from django.db import models
class Produit(models.Model):
nom = models.CharField(max_length=100)
specifications = models.JSONField(default=dict)
etiquettes = models.JSONField(default=list)
# Création avec des données JSON
ecran = Produit.objects.create(
nom='Écran 27 pouces',
specifications={
'resolution': '2560x1440',
'taille': 27,
'connectique': ['HDMI', 'DisplayPort', 'USB-C'],
'dalle': {'type': 'IPS', 'frequence': 144},
},
etiquettes=['informatique', 'bureau', 'promo'],
)
# Filtrage par clé imbriquée
ecrans_ips = Produit.objects.filter(
specifications__dalle__type='IPS'
)
# Vérifier la présence d'une clé
avec_connectique = Produit.objects.filter(
specifications__has_key='connectique'
)
# Filtrer par contenu de liste
promos = Produit.objects.filter(
etiquettes__contains=['promo']
)
Vues et middlewares asynchrones
Django 3.1 permet de définir des vues avec async def. Le framework détecte automatiquement si la vue est synchrone ou asynchrone et adapte son exécution. Les middlewares peuvent également définir des méthodes asynchrones. Cela ouvre la voie aux appels HTTP non bloquants et aux connexions WebSocket directement dans les vues Django.
import httpx
from django.http import JsonResponse
# Vue asynchrone
async def meteo_ville(request, ville):
"""Récupère la météo via une API externe sans bloquer."""
async with httpx.AsyncClient() as client:
reponse = await client.get(
f'https://api.meteo.example/v1/{ville}'
)
donnees = reponse.json()
return JsonResponse({
'ville': ville,
'temperature': donnees['temp'],
'description': donnees['description'],
})
# Middleware asynchrone
class JournalisationAsyncMiddleware:
async_capable = True
def __init__(self, get_response):
self.get_response = get_response
async def __call__(self, request):
import time
debut = time.monotonic()
response = await self.get_response(request)
duree = time.monotonic() - debut
print(f"{request.path} : {duree:.3f}s")
return response
Support de pathlib.Path
Les réglages Django acceptent désormais les objets pathlib.Path partout où un chemin de fichier est attendu. Le fichier settings.py généré utilise Path au lieu de os.path pour BASE_DIR.
# settings.py (généré par Django 3.1+)
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# Plus besoin de os.path.join
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
STATIC_ROOT = BASE_DIR / 'staticfiles'
MEDIA_ROOT = BASE_DIR / 'media'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
},
]
