Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use pagination in a Django REST framework ViewSet subclass?

I have a simple subclass of viewsets.ViewSet which looks like:

from rest_framework import viewsets
from rest_framework.response import Response

from ..models import Entry, Sitting, Source, Venue
from .serializers import (
    SittingSerializer, SittingWithEntriesSerializer,
)

class SittingViewSet(viewsets.ViewSet):

    def list(self, request, version=None):
        queryset = Sitting.objects.order_by('id')
        serializer = SittingSerializer(
            queryset, many=True, context={'request': request}
        )
        return Response(serializer.data)

    def retrieve(self, request, pk=None, version=None):
        prefetch_qs = Entry.objects.select_related('speaker')
        queryset = Sitting.objects.order_by('id') \
            .prefetch_related(Prefetch('entry_set', queryset=prefetch_qs))
        sitting = get_object_or_404(queryset, pk=pk)
        serializer = SittingWithEntriesSerializer(
            sitting, context={'request': request}
        )
        return Response(serializer.data)

However, the list view isn't paginated, as it is if you use a subclass of ModelViewSet. The settings I'm using are:

# Django Rest Framework settings:
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('pombola.api.permissions.ReadOnly',),
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'PAGE_SIZE': 10,
}

The documentation suggests looking at the source code for the mixins.ListModelMixin and generics.GenericAPIView classes, but I can't easily see how to reapply what they do to paginate results to these ViewSet methods.

Could anyone suggest what the simplest way would be to change this example to get pagination for the list view?

like image 405
Mark Longair Avatar asked Feb 25 '16 10:02

Mark Longair


2 Answers

You overrided the list method, so it doesnt paginate your data.
If you check ListModelMixins I think this might be your answer:

class SittingViewSet(
    viewsets.GenericViewSet,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin):

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(
            Sitting.objects.order_by('id')
        )

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = SittingSerializer(
                page, 
                many=True, 
                context={'request': request}
                )
            return self.get_paginated_response(serializer.data)

        serializer = SittingSerializer(
                queryset, 
                many=True, 
                context={'request': request}
                )
        return Response(serializer.data)
like image 162
Matúš Bartko Avatar answered Nov 14 '22 23:11

Matúš Bartko


Simple solution. Let's use the auth model as an example.

from django.contrib.auth.models import User

from rest_framework.pagination import PageNumberPagination
from rest_framework import viewsets

from .serializer import UserSerializer


class UserViewSet(viewsets.ViewSet):
    def list(self, request):
        queryset = User.objects.all()
        pagination = PageNumberPagination()
        qs = pagination.paginate_queryset(queryset, request)
        serializer = UserSerializer(qs, many=True)
        return pagination.get_paginated_response(serializer.data)


like image 40
Yonas Avatar answered Nov 14 '22 22:11

Yonas