Custom code for different requests in a viewset

Django allows customizing code based on action. For eg, Different serializer can be returned for different GET action. Or run someother code following the operation

class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.
    """

    # GET request without id
    def list(self, request):
        pass

    # POST request
    def create(self, request):
        pass

    # GET request with id
    def retrieve(self, request, pk=None):
        pass

    # PUT request with id
    def update(self, request, pk=None):
        pass

    # PATCH request with id
    def partial_update(self, request, pk=None):
        pass

    # DELETE request with id
    def destroy(self, request, pk=None):
        pass

Current action

Current action can be retrived with the following attribute

self.action

Accessing the object ID

Use the recipe-detail tag with id as arg

def detail_url(recipe_id):
    return reverse("recipe:recipe-detail", args=[recipe_id])

Changing serializer class and writing custom code based on action

To allow views to accept urls with ids, extend your view from ModelViewSet (Generic viewset with all request Mixins)

Override get_serializer_class in the ModelViewSet to change serializers based on action

# Extend from 'ModelViewSet' to allow urls with id
class RecipeViewSet(viewsets.ModelViewSet):
    """Manage recipes in the database"""
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    serializer_class = serializers.RecipeSerializer
    queryset = Recipe.objects.all()

    # django allows to change serializers depending on action
    # we can have differernt serializer for list and detail views
    # for this, we have to override this function
    def get_serializer_class(self):
        if self.action == 'retrieve':
            return serializers.RecipeDetailSerializer
        return self.serializer_class

    def get_queryset(self):
        return self.queryset.filter(user=self.request.user)

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

    # write custom code when GET without id is called
    def list(self, request):
        print("GET without id")
        return super().list(request)

    # write custom code when GET with ID is called
    def retrieve(self, request, pk):
        print("GET with id")
        return super().retrieve(request, pk)