• 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

Différenciez les informations de liste et de détail

Retournez plus d’informations dans le détail

Très souvent, les données en retour sont différentes selon qu’on consulte un endpoint de liste ou un endpoint de détail. En règle générale, les listes sont appelées pour être affichées. Lorsque l’utilisateur sélectionne un des éléments qui la composent, alors un autre appel est réalisé par l’application cliente afin d’obtenir plus d’informations.

Cela permet de réduire les temps de réponse en ne retournant que les informations utiles.

Dans notre cas, la liste des catégories est bien trop complète pour l’usage qui doit en être fait, et nous allons donc réduire les informations de liste, en conservant toutes nos données actuelles dans l'endpoint de détail d’une catégorie.

Améliorez le rendu du détail d’un endpoint

Améliorons notre endpoint de catégories en ne retournant que les informations minimales, dans le cas d’une liste, et détaillées, lorsque nous consultons une catégorie spécifique.

DRF nous permet au travers de ses viewsets de redéfinir la méthode get_serializer_class  qui, elle, détermine le serializer à utiliser. Par défaut, le serializer retourné est celui défini sur l’attribut de classe serializer_class  du viewset.

Lorsqu’une requête entre dans notre API, les viewsets définissent un attribut action  qui correspond à l’action que l’application client est en train de réaliser. Elle peut être :

  • list : appel en GET  sur l’URL de liste ;

  • retrieve : appel en GET  sur l’URL de détail (qui comporte alors un identifiant) ;

  • create : appel en POST  sur l’URL de liste ;

  • update : appel en PUT  sur l’URL de détail ;

  • partial_update : appel en PATCH  sur l’URL de détail ;

  • destroy : appel en DELETE  sur l’URL de détail.

class CategoryViewset(ReadOnlyModelViewSet):
 
    serializer_class = CategoryListSerializer
    # Ajoutons un attribut de classe qui nous permet de définir notre serializer de détail
    detail_serializer_class = CategoryDetailSerializer
 
    def get_queryset(self):
        return Category.objects.filter(active=True)
 
    def get_serializer_class(self):
    # Si l'action demandée est retrieve nous retournons le serializer de détail
        if self.action == 'retrieve':
            return self.detail_serializer_class
        return super().get_serializer_class()

Après avoir redémarré le serveur et avoir rafraîchit notre page, nous pourrons alors voir que les informations de la liste des catégories sont réduites, alors que le détail est plus complet.

Voyons ce processus de plus près dans le screencast ci-dessous :

C’est également le moment idéal pour mettre en place un test sur le détail d’une catégorie :

class TestCategory(ShopAPITestCase):
    def test_detail(self):
    # Nous utilisons l'url de détail
    url_detail = reverse('category-detail',kwargs={'pk': self.category.pk})
    response = self.client.get(url_detail)
    # Nous vérifions également le status code de retour ainsi que les données reçues
    self.assertEqual(response.status_code, 200)
    excepted = {
        'id': self.category.pk,
        'name': self.category.name,
        'date_created': self.format_datetime(self.category.date_created),
        'date_updated': self.format_datetime(self.category.date_updated),
        'products': self.get_product_detail_data(self.category.products.filter(active=True)),
    }
    self.assertEqual(excepted, response.json())

Nos tests s’exécutent à présent en succès !

N’hésitez pas à dissocier les données retournées selon l’action demandée dès que cela est nécessaire. Il est également possible de définir un serializer dédié à la création ou à la modification, en se basant sur l’action souhaitée par l’application cliente.

Il peut aussi être intéressant de créer et utiliser un  Mixin.  Ceci pour permettre de mutualiser le code qui permet de définir le serializer à utiliser selon la liste et le détail. Cela évitera de réécrire du code et facilitera la maintenance.

Mais un Mixin, c’est quoi ?

Un Mixin est une classe qui est composée de méthodes concrètes, utilisée en héritage multiple pour apporter des fonctionnalités aux classes qui en héritent. C'est-à-dire qui est faite pour être héritée et non pas utilisée seule. Nous les verrons de plus près dans le prochain chapitre !

À vous de jouer

À vous à présent, faites de même et améliorez l'endpoint de produits pour que la liste reste succincte, et que le détail retourne plus d’informations.

Pour réaliser cela, vous pouvez partir de la branche P2C2_exercice. Elle contient déjà ce que nous venons de faire ensemble. Une solution est proposée sur la branche P2C2_solution.

En résumé

  • L’action réalisée est définie dans l’attribut action  des viewsets, et permet de savoir précisément l’action en cours.

  • Il est possible de définir un serializer différent pour chaque action.

  • Les mixins sont une bonne façon de gérer les différents serializers à utiliser, car cette opération est très courante.

  • Utiliser différents serializers contribue à améliorer les performances de l’API.

Dissocier les serializers de liste et de détail nous permettrait par exemple d’inclure les produits et articles dans le détail d’une catégorie. N’hésitez pas à expérimenter. 

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