Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add custom route to viewsets.ModelViewSet

In the docs there is the example of methods with custom url: http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers

class SnippetViewSet(viewsets.ModelViewSet):
    ...

    @link(renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

This example add following route:

url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),

It is possible to add an url without pk param, like this?

r'^snippets/highlight/$'
like image 719
Deadly Avatar asked Feb 02 '14 09:02

Deadly


3 Answers

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.

like image 108
Roman Avatar answered Nov 17 '22 01:11

Roman


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

like image 13
Rahul Gupta Avatar answered Nov 17 '22 01:11

Rahul Gupta


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/

like image 8
beyondfloatingpoint Avatar answered Nov 17 '22 03:11

beyondfloatingpoint