How to use LimitOffSetPagination instead of PageNumberPagination in Django Rest Framework?
Asked Answered
A

2

5

I have written a code in Python using Django Rest Framework to fetch data from database(MySql) and view it in browser using Pagination(LimitOffSetPagination).But It is not working fine.But when I used PageNumberPagination it was working great. so I am posting my new code.Commented parts of my code is actually for PageNumberPagination. So just ignore it. Please tell me the necessary changes needed and help me out. The error coming is:

Exception Value: index() missing 1 required positional argument: 'request'

view.py

from rest_framework.pagination import PageNumberPagination
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from rest_framework.pagination import LimitOffsetPagination


@api_view(['GET','POST'])

def index(self, request):

  if request.method=='GET':

    all_dataobj=fetchdata.objects.all()

    page = self.paginate_queryset(all_dataobj)

     if page is not None:

      pserializer = self.get_fetchdataSerializers(page, many=True)

      return self.get_paginated_response(pserializer.data)

    pserializer = self.get_fetchdataSerializers(all_dataobj, many=True)

    return Response(pserializer.data)

    # paginator = StandardResultsSetPagination()
    # result_page = paginator.paginate_queryset(all_dataobj, request)
    # pserializer=fetchdataSerializers(result_page,many=True)
    # return paginator.get_paginated_response(pserializer.data) 


 elif request.method=='POST':

  serializer=fetchdataSerializers(data=request.data)

  if serializer.is_valid():

    serializer.save()

  return Response(serializer.data,status=status.HTTP_201_CREATED)
  return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) 

settings.py

REST_FRAMEWORK = {

      'DEFAULT_PAGINATION_CLASS': 
      'rest_framework.pagination.LimitOffsetPagination',
      'PAGE_SIZE': 10
      }

urls.py

urlpatterns = [
path('', m.index, name='index'),
]

I am even posting the pagination.py file which I was using earlier for PageNumberPagination. Please do suggest me if there is any necessary changes needed to be done or I should remove the file as a whole itself????

pagination.py

from rest_framework import pagination

class StandardResultsSetPagination(pagination.PageNumberPagination):
page_size = 10
page_query_param = 'page'
page_size_query_param = 'per_page'
max_page_size = 1000
Aerosol answered 24/6, 2019 at 9:56 Comment(0)
A
8

Actually I solved this problem myself...so felt like posting the solution...It may come in help to someone...so I am posting the view.py, pagination.py and settings.py files...

view.py

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .pagination import CustomPagination


@api_view(['GET','POST'])

def index(request):

  if request.method=='GET':

    all_dataobj=fetchdata.objects.all()

    paginator = CustomPagination()
    result_page = paginator.paginate_queryset(all_dataobj, request)

    pserializer=fetchdataSerializers(result_page,many=True)

    return paginator.get_paginated_response(pserializer.data) 


  elif request.method=='POST':

    serializer=fetchdataSerializers(data=request.data)

    if serializer.is_valid():

      serializer.save()

    return Response(serializer.data,status=status.HTTP_201_CREATED)
    return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST) 

pagination.py

    class CustomPagination(pagination.LimitOffsetPagination):

      default_limit = 1000
      max_limit = 1000000
      min_limit = 1
      min_offset = 0
      max_offset = 1000000

       def paginate_queryset(self, queryset, request, view=None):

         limit = request.query_params.get('limit')
         offset = request.query_params.get('offset')

         if limit:

            limit = int(limit)

            if limit > self.max_limit:

              raise serializers.ValidationError({"limit" : ["Limit should be less 
              than or equal to {0}".format(self.max_limit)]})

            elif limit < self.min_limit:

              raise serializers.ValidationError({"limit" : ["Limit should be greater 
              than or equal to {0}".format(self.min_limit)]})

         if offset:

           offset = int(offset)

           if offset > self.max_offset:

             raise serializers.ValidationError({"offset" : ["Offset should be less 
             than or equal to {0}".format(self.max_offset)]})

          elif offset < self.min_offset:

            raise serializers.ValidationError({"offset" : ["Offset should be greater 
            than or equal to {0}".format(self.min_offset)]})

         return super(self.__class__, self).paginate_queryset(queryset, request, 
         view)

settings.py

REST_FRAMEWORK = {
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
 }
Aerosol answered 25/6, 2019 at 7:7 Comment(0)
A
0

Another custom limitOffset pagination. I like only passing the last part of the url to frontend.The page_size and offset can also be controlled by client

from collections import OrderedDict
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.utils.urls import replace_query_param

def divide_numbers(a, b):
    if a % b:
        return (a // b) + 1
    return a // b


class StandardResultsSetPagination(LimitOffsetPagination):
    default_limit = 6
    limit_query_param = "page_size"
    offset_query_param = "offset"
    max_limit = 50



def get_next_link(self):
    if self.offset + self.limit >= self.count:  # type: ignore
           return None
    offset = self.offset + self.limit  # type: ignore
    return replace_query_param(url="", key=self.offset_query_param, val=offset)

def get_previous_link(self):
    if self.offset <= 0:
        return None

    url = replace_query_param(url="", key=self.limit_query_param, val=self.limit)

    if self.offset - self.limit <= 0:  # type: ignore
        return None

    offset = self.offset - self.limit  # type: ignore
    return replace_query_param(url="", key=self.offset_query_param, val=offset)


def get_pages(self):
    if self.limit:
        current = divide_numbers(self.offset, self.limit) + 1
        final = divide_numbers(
            self.count - self.offset, self.limit
        ) + divide_numbers(self.offset, self.limit)

        final = max(final, 1)
    else:
        current = 1
        final = 1

    if current > final:
        current = final

    return (current, final)


def get_paginated_response(self, data):
    return Response(
        OrderedDict(
            [
                ("count", self.count),
                ("next", self.get_next_link()),
                ("current", self.get_pages()[0]),
                ("pages", self.get_pages()[1]),
                ("page_size", self.limit),
                ("previous", self.get_previous_link()),
                ("results", data),
            ]
        )
    )

sample response. Achieved by overriding rest framework response to format data in a certain standard and custom response codes

{
  "code": 2020,
  "msg": "Success",
  "data": {
    "count": 15,
    "current": 2,
    "pages": 3,
    "page_size": 6,
    "next": "?offset=12",
    "prev": null,
    "results": []
  }
}
Autrey answered 19/2 at 6:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.