DjangoNoob
DjangoNoob

Reputation: 125

How to get page_size set in query into pagination metadata django rest framework

I have setup custom pagination for one of my apps, the issues I am facing is the page_size shows only the default value that is set in the app but does not change according to the values sent in the query parameter. Where am I going wrong?

class CustomPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'

    def get_paginated_response(self, data):
        return Response({"status": True,
                         "data": {
                             'results': data,
                             "meta": {
                                 'page_count':self.page.paginator.num_pages,
                                 'total_results': self.page.paginator.count,
                                 'current_page_no': self.page.number,
                                 'limit': self.page_size,
                                 'last_page': self.page.has_next()
                             }}}, 
                         status=status.HTTP_200_OK)

The output of page_size is always 10 even if I set the query parameter to a different value. Eg: it should change to 2 if the user set page_size =2 in the query parameters.

edit:

Code for the view

class ListPCAPIView(ListAPIView):
serializer_class = ListPCSerializer

def get(self, request):
    user = self.request.user
    pc = Pc.objects.filter(
        user_id=user).order_by('pc_name')
    if pc:
        page = self.paginate_queryset(pc)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
    else:
        raise CustomException(
            detail="pc list is empty.",
            status_code=status.HTTP_400_BAD_REQUEST)

Upvotes: 2

Views: 3886

Answers (2)

XPLOT1ON
XPLOT1ON

Reputation: 3213

There is a method that will help you achieve this. get_page_size(request) Yes you need to pass in the original request. Luckily, you can get it via self.request

def get_paginated_response(self, data):
    print(self.get_page_size(self.request))
    ....

In addition, to get the total number of pages needed, for the current page size and records count The following can be done.

import math
num_of_pages = math.ceil(self.page.paginator.count / self.get_page_size(self.request))

Complete Example

paginations.py

import math

from dataclasses import dataclass
from dataclasses_json import dataclass_json
from typing import Any
from rest_framework import pagination
from rest_framework.response import Response


@dataclass_json
@dataclass
class PaginationResponse:
    count: int
    next: int
    previous: int
    page_number: int
    num_of_pages: int
    page_size: int
    results: Any


class NumberPagination(pagination.PageNumberPagination):
    page_size_query_param = 'page_size'
    max_page_size = 100

    # Path Query parameter ?page=1&page_size=5
    def get_paginated_response(self, data):
        pagination_response = PaginationResponse(
            count=self.page.paginator.count,
            next=self.page.next_page_number() if self.page.has_next() else None,
            previous=self.page.previous_page_number() if self.page.has_previous() else None,
            page_number=self.page.number,
            num_of_pages=math.ceil(self.page.paginator.count / self.get_page_size(self.request)),
            results=data,
            page_size=self.get_page_size(self.request),
        ).to_dict()

        return Response(pagination_response)

settings.py

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': '<REGISTER-NumberPagination-CLASS-HERE>',
    'PAGE_SIZE': 10,
    ...
}

Hope this helps

Upvotes: 4

Will Keeling
Will Keeling

Reputation: 22994

paginate_queryset() takes the request as its second positional argument. The request is needed so that the page_size can be obtained from it.

You're not passing the request so I'm curious to understand why the view is working at all - as Python should raise a TypeError due to incorrect number of arguments.

Anyway, try updating your code to pass the request as the second argument:

page = self.paginate_queryset(pc, request)

Upvotes: 0

Related Questions