Menu
CoddyTech

Una clase por recurso

Parte de la sección API JSON del Journey de Django de Coddy. Lección 11 de 19.

task_detail ahora es una cadena de bloques if request.method == ... junto con una lista de métodos que hay que mantener sincronizada con ellos. La clase base de Django View, en la que se basan todas las vistas genéricas que usaste, se encarga de ese seguimiento.

Asigna a la clase un método por cada método HTTP, con el nombre en minúsculas. View llama al que lleva el nombre de la solicitud y responde con 405 para cualquier otro. Los valores de la URL llegan después de request, como en una vista de función, y la ruta usa .as_view(). El tema de color de un visitante como recurso:

@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 funciona con funciones. En una clase, method_decorator lo aplica a dispatch, el método por el que pasa cada solicitud.

challenge icon

Desafío

Intermedio

Convierte task_detail en una clase TaskDetail(View):

  • Métodos get, patch y delete, cada uno haciendo lo que hacía la función, incluido el 404.
  • Exímela de CSRF con method_decorator.
  • La ruta usa views.TaskDetail.as_view() y sigue llamándose task_detail.

Pulsa Run y después abre /api/tasks/1/: la tarea se muestra como antes.

Pruébalo tú mismo

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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de API JSON

Practica por tu cuenta: Playground de Django