Django Rest Framework - APIView Pagination

Viewed 26670

I have a very simple APIView, but I don't know how to setup pagination here. In this scenario I select an Event with given pk, then I get all the NewsItems assigned to this Event.

pagination_class = LimitOffsetPagination works OK when I define queryset at the beginning in ListCreateAPIView, for ex. queryset = Event.objects.all() but not with custom get:

class EventNewsItems(APIView):
    pagination_class = LimitOffsetPagination

    def get(self, request, pk, format=None):

        #user = request.user
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

        serializer = NewsItemSerializer(news, many=True, context={'request':request})
        response = Response(serializer.data, status=status.HTTP_200_OK)
        return response

Solved:

def get(self, request, pk, format=None):

    #user = request.user
    event = Event.objects.get(pk=pk)
    news = event.get_news_items().all()
    paginator = LimitOffsetPagination()
    result_page = paginator.paginate_queryset(news, request)
    serializer = NewsItemSerializer(result_page, many=True, context={'request':request})
    response = Response(serializer.data, status=status.HTTP_200_OK)
    return response
4 Answers

Another option would be inheriting from the pagination class, with fewer changes on the view class:

from rest_framework.pagination import LimitOffsetPagination

class EventNewsItems(APIView, LimitOffsetPagination):

    def get(self, request, pk, format=None):
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

        results = self.paginate_queryset(news, request, view=self)
        serializer = NewsItemSerializer(results, many=True)
        return self.get_paginated_response(serializer.data)

Another way to paginate is by using the Paginator class.

In addition to the answer query, you must set the number of pages to be displayed and the range of elements that the page will have.

The page number and item range can be provided as part of the request parameters or by the way you select.

Taking as an example the case of the question:

from django.core.paginator import Paginator

class EventNewsItems(APIView):

    def get(self, request, pk, format=None):

        #user = request.user
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

         # -----------------------------------------------------------
        page_number = self.request.query_params.get('page_number ', 1)
        page_size = self.request.query_params.get('page_size ', 10)

        paginator = Paginator(news , page_size)
        serializer = NewsItemSerializer(paginator.page(page_number) , many=True, context={'request':request})
        # -----------------------------------------------------------

        response = Response(serializer.data, status=status.HTTP_200_OK)
        return response

this approach is almost similar as "giantas" answer, but modifyed, in this case you can modify each API as you need with page_size, and you don't need to modify settings.py globally

from rest_framework.pagination import PageNumberPagination

class EventNewsItems(APIView, PageNumberPagination):
    #this will output only 3 objects per page
    page_size = 3 
    def get(self, request, pk, format=None):
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

        results = self.paginate_queryset(news, request, view=self)
        serializer = NewsItemSerializer(results, many=True)
        return self.get_paginated_response(serializer.data)
Related