Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework - APIView Pagination

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
like image 966
user3128673 Avatar asked Mar 06 '16 18:03

user3128673


People also ask

How do I Paginate in Django REST framework?

To create a custom pagination class, first create a paginations.py file in your app folder and create a class that inherits from an existing DRF paginator. The parameters given in this custom paginator class will enable you to provide a page_size query parameter to determine the size of each page.

How does Django deal with pagination?

Note that you can give Paginator a list/tuple, a Django QuerySet , or any other object with a count() or __len__() method. When determining the number of objects contained in the passed object, Paginator will first try calling count() , then fallback to using len() if the passed object has no count() method.

What is pagination programming?

Pagination is a process that is used to divide a large data into smaller discrete pages, and this process is also known as paging. Pagination is commonly used by web applications and can be seen on Google.


3 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)
like image 86
giantas Avatar answered Oct 08 '22 21:10

giantas


I have created a Q&A style example on this subject.
As a sort summary:

By utilizing the Django Rest Frameworks source code and how they handle pagination, we create the same methods inside our view class and we use them, in the same way your solution uses the default methods:

Taken from the above mentioned doc:

from rest_framework.settings import api_settings
from rest_framework.views import APIView

class MyView(APIView):
    queryset = OurModel.objects.all()
    serializer_class = OurModelSerializer
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS # cool trick right? :)

    # We need to override get method to achieve pagination
    def get(self, request):
        ...
        page = self.paginate_queryset(self.queryset)
        if page is not None:
            serializer = self.serializer_class(page, many=True)
            return self.get_paginated_response(serializer.data)

        ... Do other stuff needed (out of scope of pagination)

    # Now add the pagination handlers taken from 
    #  django-rest-framework/rest_framework/generics.py

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator

     def paginate_queryset(self, queryset):
         """
         Return a single page of results, or `None` if pagination is disabled.
         """
         if self.paginator is None:
             return None
         return self.paginator.paginate_queryset(queryset, self.request, view=self)

     def get_paginated_response(self, data):
         """
         Return a paginated style `Response` object for the given output data.
         """
         assert self.paginator is not None
         return self.paginator.get_paginated_response(data) 
like image 17
John Moutafis Avatar answered Oct 08 '22 21:10

John Moutafis


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
like image 11
Peter Paul Avatar answered Oct 08 '22 19:10

Peter Paul