Menu
CoddyTech

صنف واحد لكل مورد

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

أصبح task_detail الآن سلسلة من كتل if request.method == ... بالإضافة إلى قائمة بالطرق التي يجب أن تتوافق معها. تتولى الفئة الأساسية View في Django، التي تقع أسفل كل عرض عام استخدمته، حفظ هذه المعلومات.

أضف إلى الفئة طريقة واحدة لكل طريقة HTTP، وسمِّ كل طريقة بحروف صغيرة. تستدعي View الطريقة التي تحمل اسم الطلب، وتُرجع الحالة 405 لأي طريقة أخرى. تصل القيم الواردة من عنوان URL بعد request، كما في عرض الدالة، ويستخدم المسار .as_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 مع الدوال. أما مع الفئة، فتضع method_decorator هذا المُزيِّن على dispatch، وهي الطريقة التي يمرّ بها كل طلب.

challenge icon

التحدي

متوسط

حوّل task_detail إلى فئة TaskDetail(View):

  • الطرائق get وpatch وdelete، تؤدي كلٌّ منها ما كانت تؤديه الدالة، بما في ذلك الاستجابة 404.
  • استثنِها من حماية CSRF باستخدام method_decorator.
  • يستخدم المسار views.TaskDetail.as_view()، ويظل اسمه task_detail.

اضغط على تشغيل، ثم افتح /api/tasks/1/: ستظهر المهمة كما في السابق.

جرّب بنفسك

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))
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

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

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