Projekt: Erledigte Aufgaben löschen
Teil des Abschnitts JSON-APIs der Django-Journey von Coddy. Lektion 16 von 19.
Erledigte Aufgaben häufen sich, deshalb braucht der Tracker eine Möglichkeit, sie alle auf einmal zu löschen. Das Löschen betrifft viele Aufgaben auf einmal, nicht nur eine einzelne Aufgabe, daher bekommt es eine eigene URL. Da dabei Daten geändert werden, akzeptiert es nur POST: Browser, Linkvorschauen und Suchmaschinen senden GET-Anfragen, ohne jemanden zu fragen, daher darf ein GET niemals etwas löschen.
Ein Detail ist neu. Das delete() eines QuerySets gibt ein Paar zurück: die Anzahl der gelöschten Zeilen und ein Wörterbuch mit den Zählwerten pro Modell:
>>> Book.objects.filter(year__lt=1900).delete()
(2, {'books.Book': 2})Den Rest hast du schon früher erstellt: eine Ansicht, ihre Route, zwei Decorators und eine JSON-Antwort.
Aufgabe
SchwerFüge einen Endpunkt hinzu, der alle erledigten Aufgaben löscht.
- Füge in
tasks/views.pyeine Viewclear_donehinzu. Sie löscht alle erledigten Aufgaben und gibt{"deleted": 1}zurück, also die Anzahl der gelöschten Aufgaben. Bei jeder Methode außerPOSTwird405zurückgegeben, und der Endpunkt funktioniert ohne CSRF-Token. - Füge in
tasks/urls.pydie Route"api/tasks/clear-done/"mit dem Namenclear_donehinzu.
Führe die folgende Zeile im Tab „Shell“ aus: Sie gibt {'deleted': 1} aus, da „Call the bank“ die einzige erledigte Aufgabe war.
from django.test import Client; print(Client().post("/api/tasks/clear-done/").json())Probier es selbst
import json
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_GET, require_http_methods
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")
def task_page(request):
return render(request, "tasks/list.html", {"tasks": Task.objects.all()})
def task_row(request, pk):
task = get_object_or_404(Task, pk=pk)
return render(request, "tasks/list.html#task-row", {"task": task})
@require_GET
def stats(request):
total = Task.objects.count()
done = Task.objects.filter(done=True).count()
data = {
"total": total,
"done": done,
"open": total - done,
}
return JsonResponse(data)
@csrf_exempt
@require_http_methods(["GET", "POST"])
def task_list(request):
if request.method == "POST":
try:
data = json.loads(request.body)
except json.JSONDecodeError:
return JsonResponse({"error": "The body is not valid JSON."}, status=400)
errors = {}
title = data.get("title", "").strip()
if not title:
errors["title"] = "This field is required."
priority = data.get("priority", "normal")
if priority not in Task.Priority.values:
errors["priority"] = "Choose low, normal or high."
if errors:
return JsonResponse({"errors": errors}, status=400)
task = Task.objects.create(
title=title,
priority=priority,
)
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)
priority = request.GET.get("priority")
if priority:
tasks = tasks.filter(priority=priority)
return JsonResponse([task_to_dict(task) for task in tasks], safe=False)
def not_found():
return JsonResponse({"error": "Task not found"}, status=404)
@method_decorator(csrf_exempt, name="dispatch")
class TaskDetail(View):
def get(self, request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return not_found()
return JsonResponse(task_to_dict(task))
def patch(self, request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return not_found()
data = json.loads(request.body)
if "title" in data:
task.title = data["title"]
if "done" in data:
task.done = data["done"]
task.save()
return JsonResponse(task_to_dict(task))
def delete(self, request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return not_found()
task.delete()
return HttpResponse(status=204)
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