Mỗi tài nguyên một lớp
Thuộc phần API JSON trong hành trình Django của Coddy. Bài học 11 trên 19.
task_detail giờ là một chuỗi khối if request.method == ... cùng với danh sách các phương thức cần giữ đồng bộ. Lớp cơ sở View của Django, nằm bên dưới mọi khung nhìn tổng quát bạn đã dùng, sẽ quản lý việc đó.
Thêm vào lớp một phương thức cho mỗi phương thức HTTP, đặt tên bằng chữ thường. View gọi phương thức có tên trùng với yêu cầu và trả về mã 405 cho mọi yêu cầu khác. Các giá trị từ URL được truyền vào sau request, giống như trong khung nhìn dạng hàm, còn tuyến đường sử dụng .as_view(). Ở đây, tài nguyên là chủ đề màu của khách truy cập, được lưu trong phiên:
from django.utils.decorators import method_decorator
from django.views import View
@method_decorator(csrf_exempt, name="dispatch")
class Theme(View):
def get(self, request):
return JsonResponse({"theme": request.session.get("theme", "light")})
def put(self, request):
data = json.loads(request.body)
request.session["theme"] = data["theme"]
return JsonResponse({"theme": data["theme"]})@csrf_exempt hoạt động với các hàm. Với một lớp, method_decorator áp dụng nó cho dispatch, phương thức mà mọi yêu cầu đều đi qua.
Thử thách
Trung bìnhChuyển task_detail thành một lớp.
- Trong
tasks/views.py, nhậpViewtừdjango.viewsvàmethod_decoratortừdjango.utils.decorators. - Thay hàm và cả hai trình trang trí bằng
class TaskDetail(View). Các phương thứcget,patchvàdeletenhận(self, request, pk)và mỗi phương thức thực hiện công việc của nhánh tương ứng trước đây. - Miễn trừ lớp khỏi CSRF bằng cách đặt
method_decorator(csrf_exempt)lêndispatch. - Trong
tasks/urls.py, định tuyến đếnviews.TaskDetail.as_view(), vẫn đặt tên làtask_detail.
Mở /api/tasks/1/: Buy milk hiển thị dưới dạng JSON.
Tự làm thử
import json
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
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", {"tasks": Task.objects.all()})
@require_GET
def stats(request):
data = {
"total": Task.objects.count(),
"done": Task.objects.filter(done=True).count(),
}
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."
if errors:
return JsonResponse({"errors": errors}, status=400)
task = Task.objects.create(
title=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)
@csrf_exempt
@require_http_methods(["GET", "PATCH", "DELETE"])
def task_detail(request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return JsonResponse({"error": "Task not found"}, status=404)
if request.method == "DELETE":
task.delete()
return HttpResponse(status=204)
if request.method == "PATCH":
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))
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong API JSON
Tự luyện tập: Playground Django