Menu
CoddyTech

حذف مهمة

جزء من قسم واجهات API بصيغة JSON في رحلة Django على Coddy. الدرس 10 من 19.

ينبغي أن تختفي المهمة المكتملة، لا أن توضع عليها علامة فقط: يحذف DELETE /api/tasks/1/ المهمة 1، وبعد ذلك لا يوجد شيء لإرساله.

لهذا الغرض، يتضمن HTTP الرمز 204 No Content: نجح الطلب، ولا يحتوي الرد على متن. يكتب JsonResponse متنًا دائمًا، حتى لو كان {}. أما HttpResponse العادي، إذا اقتصر على رمز الحالة، فلا يرسل أي شيء آخر:

def mark_read(request, pk):
    Notification.objects.filter(pk=pk).update(read=True)
    return HttpResponse(status=204)

أبقِ التحقق من 404 أولًا، لكي يظل حذف مهمة غير موجودة يعيد 404.

عنوان URL واحد وثلاثة أساليب: يقرأ GET المهمة، ويغيّرها PATCH، ويحذفها DELETE. عنوان URL لكل مورد، مع استخدام الأسلوب كفعل، هو ما يُسمّيه الناس واجهة برمجة تطبيقات REST.

challenge icon

التحدي

سهل

اجعل البرامج تحذف مهمة باستخدام DELETE /api/tasks/<id>/. في tasks/views.py، اسمح باستخدام "DELETE" في task_detail، ثم احذف المهمة وأعِد الاستجابة بالحالة 204 وجسم فارغ. إذا كانت المهمة غير موجودة، فستظل الاستجابة بالحالة 404.

شغّل السطر أدناه مرتين في علامة تبويب Shell: سيطبع 204، ثم 404، لأن المهمة 1 لم تعد موجودة.

from django.test import Client; print(Client().delete("/api/tasks/1/").status_code)

جرّب بنفسك

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)


@csrf_exempt
@require_http_methods(["GET", "PATCH"])
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 == "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))

جميع دروس واجهات API بصيغة JSON

تدرّب بنفسك: Playground لـ Django