Se rendre au contenu

Django Ninja 1.3

Décorateurs globaux, FilterSchema par annotation et PatchDict
15 août 2024 par
Django Ninja 1.3
Makersquad

Date de sortie : 15 août 2024

Documentation officielle : https://django-ninja.dev

Django Ninja 1.3 est une version riche. Elle apporte des fonctionnalités que la communauté réclamait depuis un moment : des décorateurs applicables à l’ensemble d’un routeur, un système de filtres plus élégant basé sur les annotations, et un utilitaire dédié aux mises à jour partielles. Bonne lecture.


Les nouveautés principales

Décorateurs globaux sur les routeurs

Jusqu’ici, si vous vouliez appliquer un comportement transversal à plusieurs endpoints (logging, rate limiting, tracking), vous deviez soit dupliquer le décorateur sur chaque route, soit bricoler un middleware Django. Django Ninja 1.3 introduit add_decorator sur les routeurs, ce qui permet d’appliquer un décorateur à tous les endpoints d’un routeur d’un seul coup.

from functools import wraps

def log_requests(func):
    @wraps(func)
    def wrapper(request, *args, **kwargs):
        logger.info(f"Processing {request.method} {request.path}")
        return func(request, *args, **kwargs)
    return wrapper

router = Router()
router.add_decorator(log_requests)

@router.get("/products")
def list_products(request):
    ...

@router.get("/orders")
def list_orders(request):
    ...

Les deux endpoints bénéficient automatiquement du logging. Propre, centralisé, et testable indépendamment.


FilterSchema par annotation

FilterSchema existait déjà, mais la définition des filtres était parfois verbeuse. La version 1.3 permet de déclarer les filtres directement avec des annotations Python standard, sans avoir à surcharger les méthodes de filtrage manuellement.

from ninja import FilterSchema, Query

class ProductFilter(FilterSchema):
    name: str | None = None
    min_price: float | None = None
    category: str | None = None

@api.get("/products", response=list[ProductOut])
def list_products(request, filters: ProductFilter = Query(...)):
    return Product.objects.filter(**filters.dict(exclude_none=True))

Django Ninja infère les filtres ORM à partir des noms de champs et des annotations. Pour des cas plus complexes (filtres __icontains, __gte, etc.), il est toujours possible d’annoter avec Field pour spécifier l’expression de filtre exacte.


PatchDict : les mises à jour partielles enfin propres

Les mises à jour partielles (PATCH) sont un classique dans les APIs REST. Le problème : distinguer un champ absent de la requête d’un champ explicitement passé à None. Django Ninja 1.3 introduit PatchDict pour gérer exactement ce cas.

from ninja.schema import PatchDict

class ProductIn(Schema):
    name: str
    price: float
    description: str | None = None

@api.patch("/products/{product_id}", response=ProductOut)
def update_product(request, product_id: int, data: PatchDict[ProductIn]):
    product = get_object_or_404(Product, id=product_id)
    # data contient uniquement les champs fournis dans la requête
    for field, value in data.items():
        setattr(product, field, value)
    product.save()
    return product

PatchDict retourne un dictionnaire ne contenant que les champs réellement présents dans le payload, ce qui évite d’écraser involontairement des valeurs avec None.


En-têtes par défaut pour NinjaClientBase

Dans les tests, NinjaClientBase accepte maintenant des en-têtes par défaut au niveau du client. Pratique pour passer un token d’authentification une seule fois plutôt que de le répéter à chaque appel.

client = TestClient(api, headers={"Authorization": "Bearer test-token"})
response = client.get("/protected-endpoint")


Types de filtres génériques

Les types de filtres génériques permettent de créer des FilterSchema réutilisables entre plusieurs endpoints, sans dupliquer la logique de filtrage. Une bonne base pour les APIs qui exposent de nombreuses ressources avec des patterns de filtrage similaires.


Échanger avec un expert Django

Nous revenons vers vous sous 24h.


Chez Makersquad, nous accompagnons nos clients dans la conception d’application modernes et performantes avec Django .Que vous souhaitiez lancer une nouvelle API, moderniser une architecture existante ou améliorer les performances de vos services backend, notre équipe met son expertise à votre disposition pour concevoir des solutions fiables, rapides et parfaitement adaptées à vos enjeux métier.


À retenir

Django Ninja 1.3 est une version substantielle qui améliore le quotidien des développeurs sur trois axes : l’organisation du code avec les décorateurs de routeur, la lisibilité des filtres avec les annotations, et la robustesse des mises à jour partielles avec PatchDict. Si vous travaillez sur une API un peu conséquente, ces trois fonctionnalités vont rapidement devenir indispensables.

Django Ninja 1.2
Compatibilité Python 3.12.4 et correctifs de validation