Dans l'écosystème Django REST Framework (DRF), les sérialiseurs (Serializers) jouent un rôle pivot. Ils permettent de convertir des données complexes, telles que des instances de modèles ou des QuerySets, en types de données Python natifs qui peuvent ensuite être facilement rendus en JSON ou XML. Ils assurent également la désérialisation, permettant aux données entrantes d'être validées et converties en objets complexes.
1. Définition d'un Sérialiseur de base
Pour créer un sérialiseur, on hérite généralement de la classe serializers.Serializer. Contrairement au ModelSerializer, cette approche offre un contrôle total sur les champs et la logique de validation.
from rest_framework import serializers
class ProduitSerializer(serializers.Serializer):
# Définition manuelle des champs
id = serializers.IntegerField(read_only=True)
designation = serializers.CharField(max_length=100)
prix_unitaire = serializers.DecimalField(max_digits=10, decimal_places=2)
stock_disponible = serializers.IntegerField(default=0)
description = serializers.CharField(required=False, allow_blank=True)
def create(self, validated_data):
"""Logique pour créer une instance de Produit"""
return Produit.objects.create(**validated_data)
def update(self, instance, validated_data):
"""Logique pour mettre à jour une instance existante"""
instance.designation = validated_data.get('designation', instance.designation)
instance.prix_unitaire = validated_data.get('prix_unitaire', instance.prix_unitaire)
instance.stock_disponible = validated_data.get('stock_disponible', instance.stock_disponible)
instance.save()
return instance
2. Paramètres et types de champs fréquents
DRF propose une large gamme de champs pour correspondre aux types de données SQL et aux besoins de validation :
- read_only : Le champ est inclus dans la réponse mais ignoré lors de la création/mise à jour.
- write_only : Le champ est utilisé pour la soumission de données mais n'est pas exposé dans la réponse.
- required : Indique si le champ est obligatoire lors de la désérialisation.
- validators : Une liste de fonctions de validation personnalisées.
| Type de Champ | Usage |
|---|---|
BooleanField |
Valeurs booléennes (True/False). |
EmailField |
Valide le format d'une adresse courriel. |
SlugField |
Valide les chaînes de caractères de type identifiant (lettres, chiffres, tirets). |
DateTimeField |
Gère les dates et heures avec formatage spécifique. |
3. Processus de Validation
La valdiation s'effectue en appelant la méthode is_valid(). DRF permet d'ajouter des hooks de validation spécifiques.
Validation au niveau du champ
def verifier_nom_produit(value):
if 'interdit' in value.lower():
raise serializers.ValidationError("Le nom contient un mot banni.")
class ArticleSerializer(serializers.Serializer):
nom = serializers.CharField(validators=[verifier_nom_produit])
# Hook spécifique : validate_<field_name>
def validate_prix_unitaire(self, value):
if value <= 0:
raise serializers.ValidationError("Le prix doit être positif.")
return value
</field_name>
Validation globale
def validate(self, data):
"""Validation croisée entre plusieurs champs"""
if data['designation'] == data['description']:
raise serializers.ValidationError("La description doit différer du nom.")
return data
4. Intégration dans les Vues (APIView)
Voici comment utiliser le sérialiseur au sein d'une vue pour gérer les opérations CRUD.
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Produit
from .serializers import ProduitSerializer
class ProduitDetailView(APIView):
def get(self, request, pk):
produit = Produit.objects.get(pk=pk)
serializer = ProduitSerializer(produit)
return Response(serializer.data)
def put(self, request, pk):
produit = Produit.objects.get(pk=pk)
serializer = ProduitSerializer(instance=produit, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)
5. Utilisation avancée : Argument 'source' et SerializerMethodField
L'argument source permet de lier un champ de sérialiseur à un attribut spécifique du modèle ou à une méthode.
class FournisseurSerializer(serializers.Serializer):
nom_societe = serializers.CharField(source='company_name')
domaine_email = serializers.CharField(source='contact.get_domain') # Accès via relation
infos_calculées = serializers.SerializerMethodField()
def get_infos_calculées(self, obj):
# Logique Python complexe ici
return f"Fournisseur: {obj.company_name} - Grade: {obj.rating}"
6. Le ModelSerializer : l'approche accélérée
Le ModelSerializer inspecte automatiquement le modèle Django associé pour générer les champs correspondants et implémenter par défaut les méthodes create() et update().
class ProduitModelSerializer(serializers.ModelSerializer):
class Meta:
model = Produit
fields = '__all__' # Ou ['id', 'designation', 'prix_unitaire']
# Configuration spécifique des arguments
extra_kwargs = {
'stock_disponible': {'min_value': 0},
'description': {'write_only': True}
}
Le ModelSerializer est l'outil privilégié pour la majorité des cas d'utilisation standards, car il réduit considérablement la répétition de code tout en maintenant la flexibilité nécessaire via la classe interne Meta.