Rendez les Views plus génériques avec un ModelViewset

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_classqui va déterminer le serializer à utiliser ;queryset, ou réécrire la méthodeget_querysetqui 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.
En résumé
Un router permet de définir en une seule fois toutes les opérations du CRUD sur un endpoint.
Utiliser un
ModelViewsetimpose 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.
ReadOnlyModelViewsetpermet 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 !

