[Fixed]-Add custom route to viewsets.ModelViewSet

13πŸ‘

βœ…

Yes, you can do that. Just add your method in the viewset with the list_route decorator.

from rest_framework.decorators import list_route  

class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @list_route(renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        ...

It will add a url without the pk param like :

r'^snippets/highlight/$'

You can even specify the methods it supports using the methods argument in your decorator.

http://www.django-rest-framework.org/api-guide/routers/#usage

πŸ‘€Rahul Gupta

27πŸ‘

The ViewSets docs mention using action decorator:

from rest_framework.decorators import action


class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @action(detail=False, methods=['GET'], name='Get Highlight')
    def highlight(self, request, *args, **kwargs):
        queryset = models.Highlight.objects.all()

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Then just update your queryset to do whatever it needs to do.

The advantage of doing it this way is that your serialisation is preserved.

If your urls.py looks like this:

from django.contrib import admin
from django.urls import path, include

from rest_framework import routers
from snippets import viewsets

router = routers.DefaultRouter()
router.register('snippets', viewsets.SnippetViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('snippets/', include(router.urls)),
]

Then it is reachable via http://localhost:8000/snippets/highlights

To see usage for a POST, or how to change routing, see docs for routers.

πŸ‘€Roman

11πŸ‘

Since this question still turns up on first Google Page, here is up-to-date (for the late march of 2020) snippet (pun intended) to start working on your custom ModelViewSet route for single object:

from rest_framework.decorators import action


class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @action(detail=True, methods=['POST'], name='Attach meta items ids')
    def custom_action(self, request, pk=None):
        """Does something on single item."""
        queryset = Snippet.objects.get(pk=pk)
        serializer = self.get_serializer(queryset, many=False)
        return Response(serializer.data)

Having default routers from the DRF tutorial will allow you to access this route with: http://localhost:8000/snippets/<int:pk>/custom_action/

Leave a comment