Thay đổi với PATCH
Thuộc phần API JSON trong hành trình Django của Coddy. Bài học 9 trên 19.
Chương trình đánh dấu một nhiệm vụ là hoàn tất bằng cách gửi {"done": true} đến URL của nhiệm vụ đó, và không gửi gì khác. URL đó đại diện cho một nhiệm vụ, được gọi là tài nguyên (resource). Phương thức cho biết cần làm gì với tài nguyên: GET đọc tài nguyên, còn PATCH thay đổi một phần tài nguyên.
Vì vậy, một view PATCH chỉ thay đổi các trường trong phần thân. Hãy chú ý đến các giá trị mặc định. Trong API của một hiệu sách:
book.title = data.get("title", "")Chương trình chỉ gửi {"available": false} sẽ xóa tiêu đề. Trước tiên, hãy kiểm tra xem khóa có được gửi hay không: "title" in data chỉ là True khi khóa đó được gửi. Hãy đặt từng trường có trong dữ liệu, lưu một lần rồi phản hồi bằng đối tượng đã thay đổi. View cần có @csrf_exempt và phương thức mới trong require_http_methods, giống như task_list.
Thử thách
Trung bìnhCho phép chương trình thay đổi một công việc.
- Trong
tasks/views.py, thay@require_GETtrêntask_detailbằng một decorator cho phépGETvàPATCH, rồi thêm@csrf_exemptphía trên. - Với yêu cầu PATCH, đọc phần thân JSON, chỉ đặt
titlevàdonenếu chúng có trong đó, lưu lại rồi trả về công việc.
Chạy dòng bên dưới trong thẻ Shell: dòng này in ra công việc có 'done': True.
from django.test import Client; print(Client().patch("/api/tasks/1/", {"done": True}, content_type="application/json").json())Tự làm thử
import json
from django.http import 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)
@require_GET
def task_detail(request, pk):
task = Task.objects.filter(pk=pk).first()
if task is None:
return JsonResponse({"error": "Task not found"}, status=404)
return JsonResponse(task_to_dict(task))
Tất cả bài học trong API JSON
Tự luyện tập: Playground Django