TIL
Specify a different viewset serializer for lists
I often want to include related nested objects in my Django REST Framework ModelViewSets for CRUD operations, but don’t want those related objects cluttering up the list view. To accomplish this, you can return a serializer from get_serializer_class() that doesn’t include the nested relation when the ViewSet action is list. I ended up doing this on a bunch of viewsets, so I factored the logic out into a separate mixin:
from typing import Union
from rest_framework import viewsets
class ListSerializerMixin(object):
list_serializer_class = None
def get_serializer_class(
self: Union[viewsets.GenericViewSet, "ListSerializerMixin"]
):
if self.list_serializer_class and self.action == "list":
return self.list_serializer_class
return super(viewsets.GenericViewSet, self).get_serializer_class()
On your viewset, you can inherit from ListSerializerMixinMake sure to add the mixin before the ViewSet in your superclass list. then add the list_serializer_class attribute next to serializer_class instead of overriding the method directly:
class ObjectViewSet(ListSerializerMixin, viewsets.ModelViewSet):
serializer_class = ObjectDetailSerializer
list_serializer_class = ObjectListSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
return Object.objects.all().prefetch_related("related_items")
This leads to serializers that are easier to read at-a-glance, and slightly easier to write.