Menu
CoddyTech

Modifier avec PATCH

Fait partie de la section API JSON du Journey Django de Coddy. Leçon 9 sur 19.

Un programme marque une tâche comme terminée en envoyant {"done": true} à l’URL de la tâche, et rien d’autre. Cette URL représente une tâche, appelée une ressource. La méthode indique quoi en faire : GET la lit, PATCH en modifie une partie.

Une vue PATCH ne modifie donc que les champs présents dans le corps de la requête. Attention aux valeurs par défaut. Dans une API de librairie :

book.title = data.get("title", "")

Un programme qui envoie uniquement {"available": false} efface le titre. Vérifie d’abord si la clé a été envoyée : "title" in data vaut True uniquement dans ce cas. Définis chaque champ présent, enregistre une seule fois et renvoie l’objet modifié. La vue a besoin de @csrf_exempt et de la nouvelle méthode dans require_http_methods, comme c’est le cas pour task_list.

challenge icon

Défi

Moyen

Permets aux programmes de modifier une tâche.

  1. Dans tasks/views.py, remplace @require_GET sur task_detail par un décorateur qui autorise GET et PATCH, et ajoute @csrf_exempt au-dessus.
  2. Pour une requête PATCH, lis le corps JSON, définis title et done uniquement s’ils s’y trouvent, enregistre la tâche et renvoie-la.

Exécute la ligne ci-dessous dans l’onglet Shell : elle affiche la tâche avec 'done': True.

from django.test import Client; print(Client().patch("/api/tasks/1/", {"done": True}, content_type="application/json").json())

Essayez vous-même

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)


@require_GET
def task_detail(request, pk):
    task = Task.objects.filter(pk=pk).first()
    if task is None:
        return JsonResponse({"error": "Task not found"}, status=404)
    return JsonResponse(task_to_dict(task))

Toutes les leçons de API JSON

Entraînez-vous par vous-même : Playground Django