Search code examples
djangoapirestdjango-rest-frameworktastypie

django-rest-framework multiple serializer for 1 model?


Suppose you want to give out

{field1, field2, field3} on detail request.
{field1, field2} on list request.
{field1} on some other simpler list request.

I have seen examples using get_serializer_class with self.action which can handle detail vs list scenario. (https://stackoverflow.com/a/22755648/433570)

Should I define two viewsets and two url endpoints?
Or is there a better approach here?

I guess this could be applied to tastypie as well. (two resources?)


Solution

  • I haven't tested it myself but I think you can do it overriding the methods you need.

    According to the documentation (Marking extra actions for routing) you could do:

    class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.
    
    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """
    
    def list(self, request):
        pass
    
    def create(self, request):
        pass
    
    def retrieve(self, request, pk=None):
        pass
    
    def update(self, request, pk=None):
        pass
    
    def partial_update(self, request, pk=None):
        pass
    
    def destroy(self, request, pk=None):
        pass
    

    Or if you need custom methods:

    from django.contrib.auth.models import User
    from rest_framework import status
    from rest_framework import viewsets
    from rest_framework.decorators import detail_route, list_route
    from rest_framework.response import Response
    from myapp.serializers import UserSerializer, PasswordSerializer
    
    class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset that provides the standard actions
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
    @detail_route(methods=['post'])
    def set_password(self, request, pk=None):
        user = self.get_object()
        serializer = PasswordSerializer(data=request.DATA)
        if serializer.is_valid():
            user.set_password(serializer.data['password'])
            user.save()
            return Response({'status': 'password set'})
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)
    
    @list_route()
    def recent_users(self, request):
        recent_users = User.objects.all().order('-last_login')
        page = self.paginate_queryset(recent_users)
        serializer = self.get_pagination_serializer(page)
        return Response(serializer.data)