wq / django-rest-pandas

📊📈 Serves up Pandas dataframes via the Django REST Framework for use in client-side (i.e. d3.js) visualizations and offline analysis (e.g. Excel)

Home Page:https://django-rest-pandas.wq.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use as a method in a ViewSet

donatogr opened this issue · comments

Is it possibile to extend a standard DRF ViewSet with a method implementing a DRP PandasView?

I'm also interested in this - or just a way to route extra actions when having a pandasviewset.
http://www.django-rest-framework.org/api-guide/routers/#routing-for-extra-actions

Eg what I'd like to do:

/api/buildings
/api/buildings/1/doors --> give a csv with all doors for a specific building

If I use a ModelViewSet (standard) this will work (returning json) when using

@action(detail=True)
def doors(self, request, pk):

inside the viewset. If I change the viewset to a PandasViewset, it seems these actions no longer work.

Answering myself :

You can achieve this by using nested routing, with the drf-nested-routing package.

Register a nested router:

# urls.py
from rest_framework_nested import routers
building_router = routers.NestedSimpleRouter(building, 'building', lookup='building')
building_router.register('doors', views.DoorsViewset, base_name='building-doors')

And add a view:

class DoorsViewset(PandasViewSet):
    def get_queryset(self):
        print (self.kwargs)
        queryset = Doors.objects.filter(cable_id=self.kwargs['building_pk'])
        return queryset
    serializer_class = DoorsSerializer

Since most of the work happens in the serializer and renderers, you can also do this without PandasView/PandasViewSet. One option would be to override get_renderers() and explicitly set list_serializer_class, something like this:

class DoorSerializer(ModelSerializer):
    class Meta:
        list_serializer_class = PandasSerializer

class BuildingViewSet(ModelViewSet):
    def get_renderers(self):
        if self.action == 'doors':
             return [PandasCSVRenderer(), ...]
        else:
            return super().get_renderers()

    @action(detail=True)
    def doors(self, request, pk):
        queryset = Doors.objects.filter(...)
        return DoorSerializer(queryset, many=True).data

I added some more information to the README.