Erreurs de validation JSON
Fait partie de la section API JSON du Journey Django de Coddy. Leçon 7 sur 19.
Actuellement, un POST sans titre provoque une erreur KeyError, et Django répond par 500 Server Error, ce qui n'indique pas au programme ce qu'il faut corriger.
Lorsque le problème vient des données, réponds avec 400 Bad Request et indique ce qui ne va pas en JSON, un message par champ, comme un formulaire Django conserve ses erreurs. Une librairie qui vérifie l'année d'un livre :
errors = {}
year = data.get("year")
if not isinstance(year, int) or year < 0:
errors["year"] = "Enter the year as a whole number."
if errors:
return JsonResponse({"errors": errors}, status=400)Il reste deux pièges. Un titre composé uniquement d'espaces n'est pas vide, mais " ".strip() vaut "". Un corps qui n'est pas du JSON fait lever json.loads une exception json.JSONDecodeError. Intercepte-la avec try et except, et réponds avec 400 au lieu de planter.
Défi
MoyenFais en sorte que POST /api/tasks/ refuse les données incorrectes avec le statut 400.
- Dans
task_list, interceptejson.JSONDecodeErrorautour dejson.loadset réponds avec{"error": "The body is not valid JSON."}. - Si le titre est manquant ou vide après suppression des espaces, n’enregistre rien et réponds avec
{"errors": {"title": "This field is required."}}. - Sinon, crée la tâche avec le titre débarrassé des espaces.
Dans l’onglet Shell, la ligne ci-dessous affiche This field is required.
from django.test import Client; print(Client().post("/api/tasks/", {"title": " "}, content_type="application/json").json())Essayez vous-même
import json
from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from .models import Task
def task_to_dict(task):
return {
"id": task.id,
"title": task.title,
"done": task.done,
"priority": task.priority,
}
def home(request):
return render(request, "tasks/home.html", {"tasks": Task.objects.all()})
def stats(request):
data = {
"total": Task.objects.count(),
"done": Task.objects.filter(done=True).count(),
}
return JsonResponse(data)
@csrf_exempt
def task_list(request):
if request.method == "POST":
data = json.loads(request.body)
task = Task.objects.create(
title=data["title"],
priority=data.get("priority", "normal"),
)
return JsonResponse(task_to_dict(task), status=201)
tasks = Task.objects.all()
done = request.GET.get("done")
if done == "true":
tasks = tasks.filter(done=True)
elif done == "false":
tasks = tasks.filter(done=False)
return JsonResponse([task_to_dict(task) for task in tasks], safe=False)
def task_detail(request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return JsonResponse({"error": "Task not found"}, status=404)
return JsonResponse(task_to_dict(task))
Toutes les leçons de API JSON
2Lire les requêtes
Filtrer avec une requêteCréer avec POST5Projet : Trier le travail
Projet : Les prioritésProjet : Effacer les tâches terminéesEntraînez-vous par vous-même : Playground Django