Progetto: cancellare le attività completate
Fa parte della sezione API JSON del percorso Django di Coddy. Lezione 16 di 19.
Le attività completate si accumulano, quindi il tracker ha bisogno di un modo per eliminarle tutte in una volta. Questa azione non è una risorsa di una singola attività, quindi ha un proprio URL e, poiché modifica i dati, accetta solo POST: browser, anteprime dei link e motori di ricerca inviano richieste GET senza chiedere a nessuno, quindi una richiesta GET non deve mai eliminare nulla.
C'è un dettaglio nuovo. Il metodo delete() di un QuerySet restituisce una coppia: il numero di righe eliminate e un dizionario con i conteggi per modello:
>>> Book.objects.filter(year__lt=1900).delete()
(2, {'books.Book': 2})Il resto lo hai già realizzato in precedenza: una vista, il relativo percorso, due decoratori e una risposta JSON.
Sfida
DifficileAggiungi POST /api/tasks/clear-done/, con il nome di route clear_done:
- Elimina tutte le attività completate e restituisce
{"deleted": 1}, il numero di attività eliminate. - Qualsiasi altro metodo restituisce 405.
- Funziona senza token CSRF.
Premi Esegui, poi nella scheda Shell: from django.test import Client; print(Client().post("/api/tasks/clear-done/").json())
Provalo tu
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)
Tutte le lezioni di API JSON
2Lettura delle richieste
Filtrare con una queryCreare con POST5Progetto: organizzare il lavoro
Progetto: le prioritàProgetto: cancellare le attività completateEsercitati da solo: Playground Django