[Django]-Django Rest Framework – APIView Pagination

60👍

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)

19👍

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) 

12👍

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

5👍

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)

0👍

Add Pagination for multiple querysets and serializers in single APIVIew class

Sometimes we get into a scenario where we need to show a custom jsonResponse data, Suppose you are in a situation where you need to show 3 different model data in one single dictionary(JsonResponse), in that case our default django restframework classes ain’t helpful, SO if you are in that situation or want to add paginations to your code which we made with APIVIew class, then here’s all you need to look for.

Code Example(views.py):

class UserPostsAPIView(APIView, CustomPagination):
permission_classes = (permissions.AllowAny,)

def get(self, request, user_id, *args, **kwargs):
    p = Post.objects.filter(user_id=user_id).order_by('-created_at').all()
    
    pd={}
    p_lst=[]
    all=[]
    # user_param = request.GET.get('user_id',None)
    
    for i in range(len(p)): 
        pd['post']=p[i]
        p_lst.append(p[i])

        pl=PostLike.objects.filter(post_id=p[i].post_id).all()
        pc=PostComment.objects.filter(post_id=p[i].post_id).all()
        
        if UserConnections.objects.filter(user=p[i].user_id.user_id,following__user_id=user_id):
            u1=True
        else: 
            u1=False
        try:
            user_followers_count=str(UserConnections.objects.filter(user=p[i].user_id.user_id)[0].followers.all().count())

        except:
            user_followers_count=0
        is_liked=None
        if PostLike.objects.filter(post_id=p[i],user_id=user_id):
            is_liked=True
        else:
            is_liked=False
        
        all.append(
            {
            "post_id":str(PostsViewSerializer(p[i]).data['post_id']),
            "user_id":str(PostsViewSerializer(p[i]).data['user_id']['user_id']),
            "user_name":str(PostsViewSerializer(p[i]).data['user_id']['name']),
            "user_image":str(PostsViewSerializer(p[i]).data['user_id']['image']),
            "tags": str(PostsViewSerializer(p[i]).data['tags']),
            "activities": str(PostsViewSerializer(p[i]).data['activities']),
            "image": str(PostsViewSerializer(p[i]).data['image']),
            "description": str(PostsViewSerializer(p[i]).data['description']),
            "location": str(PostsViewSerializer(p[i]).data['location']),
            "created_at": str(PostsViewSerializer(p[i]).data['created_at']),
            "updated_at": str(PostsViewSerializer(p[i]).data['updated_at']),
            "is_liked": is_liked,
            "is_following": u1,
            "user_followers_count": user_followers_count,
            "total_likes_count": str(pl.count()),
            "total_comments_count": str(pc.count()),
            "recent_comments":PostCommentSerializer(pc.order_by('-created_at')[:5],many=True).data
             }
            )
    page = self.paginate_queryset(all, request)
    if page is not None:
        return self.get_paginated_response(page)
    return Response([all])

pagination.py

from rest_framework import pagination

class CustomPagination(pagination.PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 50
    #page_query_param = 'p'

STEP 1:- class UserPostsAPIView(APIView, CustomPagination): we need to first pass the class which we just
defined in pagination.py file above.

STEP 2: do this according to your logic of code;
page = self.paginate_queryset(all, request)
THIRD STEP: paginate your queryset data while checking if page is not none and according to it pass the response

if page is not None:
            return self.get_paginated_response(page)
        return Response([all])

Let me know if this lil effort was helpful to you or not :), Leave a comment if you stuck soemwhere, i would love to help you <3

Leave a comment