JSON-Validierungsfehler
Teil des Abschnitts JSON-APIs der Django-Journey von Coddy. Lektion 7 von 19.
Derzeit führt ein POST ohne Titel zu einem Absturz mit KeyError, und Django antwortet mit 500 Server Error, wodurch dem Programm nicht mitgeteilt wird, was behoben werden muss.
Wenn die Daten das Problem sind, antworte mit 400 Bad Request und gib in JSON an, was nicht stimmt: eine Meldung pro Feld, so wie ein Django-Formular seine Fehler speichert. Eine Buchhandlung überprüft das Jahr eines Buches:
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)Zwei Fallstricke bleiben. Ein Titel, der nur aus Leerzeichen besteht, ist nicht leer, aber " ".strip() ist "". Und bei einem Textkörper, der kein JSON ist, löst json.loads einen Fehler vom Typ json.JSONDecodeError aus, den try und except in eine 400-Antwort umwandeln. Ein 4xx-Status bedeutet, dass der Aufrufer etwas Falsches gesendet hat; ein 5xx bedeutet, dass dein Code einen Fehler enthält.
Aufgabe
MittelSorge dafür, dass POST /api/tasks/ bei ungültigen Daten mit 400 antwortet:
- Kein Titel oder nur Leerzeichen:
{"errors": {"title": "This field is required."}}, und es wird nichts gespeichert. - Ein Body, der kein JSON ist:
{"error": "The body is not valid JSON."}. - Ein gültiger Titel wird ohne die Leerzeichen davor und danach gespeichert.
Klicke auf Run und dann im Tab Shell auf: from django.test import Client; print(Client().post("/api/tasks/", {"title": " "}, content_type="application/json").json())
Probier es selbst
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))
Alle Lektionen in JSON-APIs
2Anfragen lesen
Mit einer Query filternMit POST erstellen5Projekt: Arbeit sortieren
Projekt: PrioritätenProjekt: Erledigte Aufgaben löschenÜbe selbstständig: Django-Playground