Débutant
🧠 Fondamentaux
10 XP
0 personnes ont réussi
Serializer avec validation de champs
Tu as deja vu qu'un serializer filtre les champs. Mais en production, ca ne suffit pas. Imagine un formulaire de produit : un utilisateur qui envoie un prix de -50 euros ou un titre rempli d'espaces, ca va poser probleme. Il faut valider le contenu de chaque champ.
Dans DRF, tu ecris des methodes validate_<nom_du_champ> sur ton serializer. Si la valeur est invalide, la methode leve une erreur. Si elle est valide, elle retourne la valeur nettoyee. Le serializer les appelle automatiquement grace a l'introspection Python.
Voici le principe :
class MonSerializer: fields = ['title', 'price']
def validate_price(self, value): if value < 0: raise ValueError("Le prix doit etre positif") return value
Tu vas creer une classe ProductSerializer avec les champs 'title', 'price' et 'category'. Elle doit avoir :
validate_title(value) : leve ValueError si le titre est vide ou ne contient que des espaces. Sinon retourne le titre nettoye avec strip().
validate_price(value) : leve ValueError si le prix n'est pas un nombre (int ou float) ou s'il est negatif. Sinon retourne le prix.
validate(data) : verifie que tous les champs sont presents, puis appelle validate_<champ> pour chaque champ qui a un validateur. Retourne {'data': donnees_validees} si tout est bon, ou {'errors': dictionnaire_des_erreurs} sinon.
s.validate({'title': '', 'price': -5, 'category': 'oops'}) renvoie {'errors': {'title': 'Le titre ne peut pas etre vide', 'price': 'Le prix doit etre positif ou nul'}}
Tests (4/5)
Données valides
s = ProductSerializer()
r = s.validate({'title': 'Widget', 'price': 9.99, 'category': 'gadget'})
assert 'data' in r
assert r['data']['title'] == 'Widget'
Titre nettoye
s = ProductSerializer()
r = s.validate({'title': ' Widget ', 'price': 5, 'category': 'x'})
assert r['data']['title'] == 'Widget'
Titre vide
s = ProductSerializer()
r = s.validate({'title': '', 'price': 5, 'category': 'x'})
assert 'errors' in r
assert 'title' in r['errors']
Prix negatif
s = ProductSerializer()
r = s.validate({'title': 'Ok', 'price': -1, 'category': 'x'})
assert 'errors' in r
assert 'price' in r['errors']
+ 0 tests cachés
Indices (3 disponibles)
Solution officielle
class ProductSerializer:
fields = ['title', 'price', 'category']
def validate_title(self, value):
if not isinstance(value, str) or not value.strip():
raise ValueError("Le titre ne peut pas etre vide")
return value.strip()
def validate_price(self, value):
if not isinstance(value, (int, float)):
raise ValueError("Le prix doit etre un nombre")
if value < 0:
raise ValueError("Le prix doit etre positif ou nul")
return value
def validate(self, data):
missing = [f for f in self.fields if f not in data]
if missing:
return {'errors': {f: 'Ce champ est requis' for f in missing}}
errors = {}
validated = {}
for field in self.fields:
validator = gétattr(self, f'validate_{field}', None)
if validator:
try:
validated[field] = validator(data[field])
except ValueError as e:
errors[field] = str(e)
else:
validated[field] = data[field]
if errors:
return {'errors': errors}
return {'data': validated}