61👍
I’ve adapted an answer from “Django rest framework, use different serializers in the same ModelViewSet” that serves me very well, and I hope you’ll find useful:
class MyModelViewSet(viewsets.MyModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelListSerializer
detail_serializer_class = MyModelDetailSerializer
def get_serializer_class(self):
if self.action == 'retrieve':
if hasattr(self, 'detail_serializer_class'):
return self.detail_serializer_class
return super(MyModelViewSet, self).get_serializer_class()
In this case, you’re just specifying your two serializers and using the one depending on the action. However, this can be made more general (for all actions) as follows:
class MyModelViewSet(viewsets.MyModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
action_serializers = {
'retrieve': MyModelDetailSerializer,
'list': MyModelListSerializer,
'create': MyModelCreateSerializer
}
def get_serializer_class(self):
if hasattr(self, 'action_serializers'):
return self.action_serializers.get(self.action, self.serializer_class)
return super(MyModelViewSet, self).get_serializer_class()
1👍
Viewsets extend the class GenericAPIView, so you can use this part of the documentation to solve your problem. Basically, what you need is to override get_serializer_class and to return a different serializer based on your request.
- [Django]-Django – after login, redirect user to his custom page –> mysite.com/username
- [Django]-What is the Simplest Possible Payment Gateway to Implement? (using Django)
- [Django]-Can't install via pip because of egg_info error
0👍
I’ve created this small package for this job. drf_custom_viewsets.
It has CustomSerializerViewSet
, which inherits from ModelViewSet
, which lets you set different serializers for different actions.
- [Django]-Direct assignment to the forward side of a many-to-many set is prohibited. Use emails_for_help.set() instead
- [Django]-Mysql error : ERROR 1018 (HY000): Can't read dir of '.' (errno: 13)
- [Django]-What's the purpose of Django setting ‘SECRET_KEY’?
0👍
As of 2021, I will do it differently, a better and more generic way around is doing something like this:
class PlayersListViewSet(viewsets.ModelViewSet):
queryset = Player.objects.all()
serializer_class = PlayersListSerializer
http_method_names = ['get', 'post']
pagination_class = None
filter_backends = [filters.OrderingFilter]
ordering_fields = ['name']
serializer_class_by_action = {
'retrieve': PlayersDetailSerializer,
'list': PlayersListSerializer,
}
def get_serializer_class(self):
if hasattr(self, 'serializer_class_by_action'):
return self.serializer_class_by_action.get(self.action, self.serializer_class)
return super(MyModelViewSet, self).get_serializer_class()
def get_queryset(self):
queryset = Player.objects.all()
team_id = self.request.query_params.get('team', None)
if team_id:
try:
queryset = queryset.filter(team=team_id)
except ValueError:
raise exceptions.ParseError()
return queryset
Here action
is the method used by the serializer, list
in case of def list
, retrieve
in case of def retrieve
and so on..
- [Django]-Possible to host a django site on github pages?
- [Django]-Python (and Django) best import practices
- [Django]-Django, creating a custom 500/404 error page
0👍
Thanks to @bbengfort, I’ve provided a simple solution without the need to create a new ViewSet
.
Different Serializer Per Action In the ViewSet in Django
TL;DR
In the following code, we are overriding get_serializer_class
based on Django documentation and we’re specifying different serializers per action if it’s needed:
Views.py
class TestAPIView(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = TestAPISerializer
serializer_class_by_action = {
'update_me': UpdateMeSerializer,
}
def get_serializer_class(self):
if hasattr(self, 'serializer_class_by_action'):
return self.serializer_class_by_action.get(self.action, self.serializer_class)
return self.serializer_class
@action(detail=True, methods=['patch'], url_name='Update Me', url_path='updateme')
def update_me(self, request, pk=None):
# Write your own logic
return Response("OK")
Serializers.py
class UpdateMeSerializer(serializers.Serializer):
count = serializers.CharField(required=False, allow_null=True, default=10)
class Meta:
fields = ['count']
- [Django]-Python MySQLDB: Get the result of fetchall in a list
- [Django]-Import error cannot import name execute_manager in windows environment
- [Django]-How to annotate Count with a condition in a Django queryset