• 10 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 28/11/2023

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 CreateViewUpdateViewDeleteViewListView  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éthode get_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.

Quand nous consultons notre Category Viewset List, les seules actions qui sont permises sont GET, HEAD et OPTIONS
Seules les actions GET, HEAD et OPTIONS sont 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 !

Exemple de certificat de réussite
Exemple de certificat de réussite