Proyek: Menghapus Tugas yang Selesai
Termasuk bagian API JSON dalam perjalanan Django di Coddy. Pelajaran 16 dari 19.
Tugas yang selesai terus menumpuk, jadi pelacak perlu cara untuk menghapus semuanya sekaligus. Tindakan itu bukan resource milik satu tugas, jadi tindakan tersebut memiliki URL sendiri. Karena tindakan itu mengubah data, tindakan tersebut hanya menerima POST: browser, pratinjau tautan, dan mesin pencari mengirim GET tanpa meminta izin siapa pun, jadi GET tidak boleh menghapus apa pun.
Ada satu detail baru. QuerySet delete() mengembalikan sepasang nilai, yaitu jumlah baris yang dihapus dan dictionary berisi jumlah untuk setiap model:
>>> Book.objects.filter(year__lt=1900).delete()
(2, {'books.Book': 2})Selebihnya sudah pernah kamu buat: sebuah view, rutenya, dua decorator, dan jawaban JSON.
Tantangan
SulitTambahkan POST /api/tasks/clear-done/, dengan rute bernama clear_done:
- Rute ini menghapus semua tugas yang sudah selesai dan mengembalikan
{"deleted": 1}, jumlah yang dihapus. - Metode lain apa pun mengembalikan 405.
- Rute ini berfungsi tanpa token CSRF.
Tekan Jalankan, lalu di tab Shell: from django.test import Client; print(Client().post("/api/tasks/clear-done/").json())
Coba sendiri
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)
Semua pelajaran di API JSON
2Membaca Permintaan
Memfilter dengan QueryMembuat dengan POST5Proyek: Mengurutkan Pekerjaan
Proyek: PrioritasProyek: Menghapus Tugas yang SelesaiLatihan sendiri: Playground Django