Maîtriser la sérialisation avec Django REST Framework

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.

Étiquettes: django-rest-framework Python serializers api-development

Publié le 29 octobre à 00h18