Menu
CoddyTech

Eliminar una tarea

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

Una tarea terminada debe desaparecer, no solo quedar marcada: DELETE /api/tasks/1/ elimina la tarea 1, y después no hay nada que enviar de vuelta.

Para eso, HTTP tiene 204 No Content: la solicitud se procesó correctamente y la respuesta no tiene cuerpo. Un JsonResponse siempre escribe un cuerpo, incluso {}. Un HttpResponse simple, solo con un estado, no envía nada más:

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

Mantén primero la comprobación del 404 para que eliminar una tarea inexistente siga respondiendo con 404.

Una URL, tres métodos: GET lee la tarea, PATCH la modifica y DELETE la elimina. Una URL por recurso, con el método como verbo, es lo que se conoce como una API REST.

challenge icon

Desafío

Fácil

Permite que los programas eliminen una tarea con DELETE /api/tasks/<id>/. En tasks/views.py, permite "DELETE" en task_detail, luego elimina la tarea y responde con el estado 204 y un cuerpo vacío. Si falta la tarea, la respuesta sigue siendo 404.

Ejecuta dos veces la línea de abajo en la pestaña Shell: imprime 204 y después 404, porque la tarea 1 ya no está.

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

Pruébalo tú mismo

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))

Todas las lecciones de API JSON

Practica por tu cuenta: Playground de Django