Dự án: Xóa các việc đã hoàn thành
Thuộc phần API JSON trong hành trình Django của Coddy. Bài học 16 trên 19.
Các công việc đã hoàn thành cứ dồn lại, vì vậy trình theo dõi cần có cách xóa chúng cùng lúc. Thao tác xóa áp dụng cho nhiều công việc cùng lúc, không phải chỉ một công việc, nên nó có URL riêng. Vì thao tác này làm thay đổi dữ liệu, nó chỉ chấp nhận POST: trình duyệt, bản xem trước liên kết và công cụ tìm kiếm gửi yêu cầu GET mà không hỏi ai, vì vậy yêu cầu GET tuyệt đối không được xóa dữ liệu.
Có một chi tiết mới. Phương thức delete() của QuerySet trả về một cặp gồm số hàng đã xóa và một từ điển chứa số lượng theo từng mô hình:
>>> Book.objects.filter(year__lt=1900).delete()
(2, {'books.Book': 2})Những phần còn lại bạn đã xây dựng trước đây: một khung nhìn, tuyến đường của nó, hai bộ trang trí và một phản hồi JSON.
Thử thách
KhóThêm một endpoint để xóa mọi nhiệm vụ đã hoàn thành.
- Trong
tasks/views.py, thêm một viewclear_done. View này xóa mọi nhiệm vụ đã hoàn thành và trả về{"deleted": 1}, trong đó số 1 là số nhiệm vụ đã xóa. Mọi phương thức ngoàiPOSTđều nhận405, và endpoint này hoạt động mà không cần CSRF token. - Trong
tasks/urls.py, thêm route"api/tasks/clear-done/"có tênclear_done.
Chạy dòng bên dưới trong thẻ Shell: dòng này in ra {'deleted': 1}, vì Call the bank là nhiệm vụ duy nhất đã hoàn thành.
from django.test import Client; print(Client().post("/api/tasks/clear-done/").json())Tự làm thử
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)
Tất cả bài học trong API JSON
Tự luyện tập: Playground Django