Menu
CoddyTech

פרויקט: ניקוי משימות שהושלמו

חלק מהיחידה ממשקי API של JSON במסלול ה-Django של Coddy. שיעור 16 מתוך 19.

המשימות שהושלמו נערמות, ולכן כלי המעקב זקוק לדרך לנקות את כולן בבת אחת. הפעולה הזאת אינה משאב של משימה אחת, ולכן יש לה URL משלה, ומכיוון שהיא משנה נתונים, היא מקבלת רק POST: דפדפנים, תצוגות מקדימות של קישורים ומנועי חיפוש שולחים בקשות GET בלי לשאול איש, ולכן בקשת GET לעולם לא צריכה למחוק.

פרט אחד חדש כאן. הקריאה delete() של QuerySet מחזירה זוג: מספר השורות שנמחקו ומילון של ספירות לפי מודל:

>>> Book.objects.filter(year__lt=1900).delete()
(2, {'books.Book': 2})

את כל השאר כבר בנית בעבר: תצוגה, נתיב עבורה, שני דקורטורים ותשובת JSON.

challenge icon

אתגר

קשה

הוסף את POST /api/tasks/clear-done/, נתיב בשם clear_done:

  • הוא מוחק כל משימה שהושלמה ומחזיר {"deleted": 1}, את מספר המשימות שנמחקו.
  • כל שיטה אחרת מחזירה 405.
  • הוא פועל ללא אסימון CSRF.

לחץ על Run, ואז בכרטיסייה Shell: from django.test import Client; print(Client().post("/api/tasks/clear-done/").json())

נסו בעצמכם

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)

כל השיעורים ביחידה ממשקי API של JSON

תרגלו בעצמכם: Django אונליין