Mettez en place un router
Plutôt que de créer nos URL et de redéfinir nos méthodes une à une, DRF propose des classes héritables pour nos vues, qui sont les ModelViewsets.
Elles permettent la mise en place rapide de toutes les actions du CRUD pour un model donné.
Utiliser un ModelViewset nécessite d’utiliser une autre façon de définir nos URL. Cela se fait au travers d’un router.
Un router, c’est quoi ?
Un router permet de définir automatiquement toutes les URL accessibles pour un endpoint donné. Il va à la fois permettre de définir :
L’URL
/api/category/
, qui permet de réaliser des actions globales qui ne concernent pas directement une entité précise, comme la récupération de la liste des entités ou la création d’une nouvelle.L’URL
/api/category/<pk>/
, qui en acceptant un paramètre correspondant à l’identifiant d’une entité, va permettre de réaliser des actions sur celle-ci, comme obtenir des informations, la modifier ou la supprimer.
Mettons en place notre router dans notre fichier urls.py
et supprimons notre ancien endpoint :
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from shop.views import CategoryViewset
# Ici nous créons notre routeur
router = routers.SimpleRouter()
# Puis lui déclarons une url basée sur le mot clé ‘category’ et notre view
# afin que l’url générée soit celle que nous souhaitons ‘/api/category/’
router.register('category', CategoryViewset, basename='category')
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('api/', include(router.urls)) # Il faut bien penser à ajouter les urls du router dans la liste des urls disponibles.
]
Le router se définit en amont de la définition de urlpatterns
. Les URL sont incluses avec un include
au travers de la propriété router.urls
.
Notons également qu’il n’est plus nécessaire d'appeler .as_view()
, le router le fait pour nous lorsqu’il génère les URL.
Transformez une ApiView en ModelViewset
À présent, nous devons transformer notre ApiView
en un ModelViewset
pour que notre vue puisse être connectée à notre routeur.
Un ModelViewset
est comparable à une super vue Django qui regroupe à la fois CreateView
, UpdateView
, DeleteView
, ListView
et DetailView
.
Il faut impérativement lui définir deux attributs de classe :
serializer_class
qui va déterminer le serializer à utiliser ;queryset
, ou réécrire la méthodeget_queryset
qui doit retourner un Queryset des éléments à retourner.
from rest_framework.viewsets import ModelViewSet
from shop.models import Category
from shop.serializers import CategorySerializer
class CategoryViewset(ModelViewSet):
serializer_class = CategorySerializer
def get_queryset(self):
return Category.objects.all()
Nous pouvons dès à présent retester notre API à l’adressehttp://127.0.0.1:8000/api/category/
.
Le résultat est identique à ce que nous avions précédemment. La différence étant qu’il nous est maintenant possible de réaliser directement les autres opérations du CRUD. Le formulaire en bas de page vous invite directement à réaliser un POST pour créer une nouvelle catégorie.
Le détail d’une catégorie est également visible en ajoutant son identifiant dans l’URL, par exemple http://127.0.0.1:8000/api/category/1/
. La page vous propose alors de réaliser les actions PUT, PATCH (dans l’onglet « Raw data ») et DELETE sur l’entité consultée.
Ne permettez que la lecture
Vous l’aurez sûrement remarqué, nous pouvons créer de nouvelles catégories ; dans la pratique, permettre la création, la modification et la suppression sur un endpoint public comme le nôtre n’est pas conseillé.
Nous allons donc faire en sorte que notre endpoint ne permette que la lecture, car son but est d’afficher à nos utilisateurs la liste des catégories disponibles sur la boutique.
Pour cela, DRF nous propose un autre type de ModelViewset
. Il s’agit du ReadOnlyModelViewset
qui, comme son nom l’indique, ne permet que la lecture.
Modifions notre vue pour limiter les opérations disponibles. Nous allons faire étendre la vue CategoryViewset
avec le viewset ReadOnlyModelViewset
au lieu du ModelViewset
actuel.
from rest_framework.viewsets import ReadOnlyModelViewSet
from shop.models import Category
from shop.serializers import CategorySerializer
class CategoryViewset(ReadOnlyModelViewSet):
serializer_class = CategorySerializer
def get_queryset(self):
return Category.objects.all()
Si nous consultons à présent notre API, nous pouvons constater que toutes les options autres que la lecture ne sont plus permises.
Suivez-moi dans le screencast ci-dessous pour voir comment j'ai mis en place un ReadOnlyModelViewset
:
À vous de jouer
Notre endpoint de consultation de produits ne doit également permettre que la lecture. Entraînez-vous dans l’utilisation des Viewsets
pour passer cet endpoint en « lecture seule ».
Pour réaliser cela, vous pouvez partir de la branche P1C4_exercice. Elle contient déjà ce que nous venons de faire ensemble.
Une solution est proposée sur la branche P1C4_solution.
En résumé
Un router permet de définir en une seule fois toutes les opérations du CRUD sur un endpoint.
Utiliser un
ModelViewset
impose d’utiliser un router pour définir ses URL.Lors de l’utilisation d’un
ModelViewset
, il faut définir :le serializer à utiliser avec l’attribut de classe
serializer_class
;le jeu de données qui sera retourné en réécrivant la méthode
get_queryset
.
ReadOnlyModelViewset
permet de limiter les accès à la lecture seule.
Les Viewsets sont très souvent les vues à privilégier, nous allons dès maintenant voir comment les personnaliser et les adapter avec plus de précision à nos besoins. Suivez-moi au prochain chapitre !