jscriptor
jscriptor

Reputation: 845

Django Rest 'PageNumberPagination' object has no attribute 'page' error

I have a function based Django API as shown in this sample:

@api_view(['GET'])
def findData(request):
    dataId = request.GET['dataId']
    page_query_param = 'page'
    page_size = request.GET['page_size']
    paginator = PageNumberPagination()
    paginator.page_size = page_size
    paginator.page_query_param = page_query_param
    qry_set = Data.objects.all()
    serializer = dataIdSerializer(qry_set, many=True)
    theData= serializer.data
    return Response(paginator.get_paginated_response(theData))

But I keep getting this error:

AttributeError: 'PageNumberPagination' object has no attribute 'page'

I tried setting

paginator.page_query_param = page_query_param

But still same problem. Please advise of how to fix.

Upvotes: 5

Views: 7015

Answers (4)

Ruturaj Singare
Ruturaj Singare

Reputation: 17

Need to add DEFAULT_PAGINATION_CLASS & PAGE_SIZE values in REST_FRAMEWORK dictionary which is in settings.py of your project.

i.e

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 5

}

Upvotes: 0

Animesh Kumar
Animesh Kumar

Reputation: 322

For me adding this to the settings.py fixed the issue.

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10    # the size of one page
}

Upvotes: 0

Yonas
Yonas

Reputation: 141

The problem is that page is set on PageNumberPagination when .paginate_queryset() is called.

Therefore, you need to call .paginate_queryset() on your paginator and pass the queryset and the request.

When you instantiate your serializer, pass the result you got from calling .paginate_queryset() instead of qry_set

Once you're done with that, DRF will throw another exception since you put paginator.get_paginated_response(theData) in Response. To resolve that, just return paginator.get_paginated_response(theData).

And finally your code will look like this:

def findData(request):
    dataId = request.GET['dataId']
    page_query_param = 'page'
    page_size = request.GET['page_size']
    paginator = PageNumberPagination()
    paginator.page_size = page_size
    paginator.page_query_param = page_query_param
    qry_set = Data.objects.all()
    p = paginator.paginate_queryset(queryset=qry_set, request=request) # change 1
    serializer = dataIdSerializer(p, many=True) # change 2
    theData= serializer.data
    return paginator.get_paginated_response(theData) # change 3

Upvotes: 7

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477513

It is likely more effective to use a ListView, not only this will remove a lot of boilerplate code, but also is likely less error prone. You can just subclass the paginator to your own:

class MyPaginator(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000

Then in the ListView, we can make use of the MyPaginator:

from rest_framework import generics

class DataListView(generics.ListAPIView):
    queryset = Data.objects.all()
    serializer_class = dataIdSerializer
    pagination_class = MyPaginator

    def get_queryset(self, *args, **kwargs):
        dataId = self.request.GET['dataId']
        super().get_queryset(*args, **kwargs).filter(
            # …
        )

Here you can filter the queryset in the get_queryset method to only use Data objects that satisfy a given condition.

In the urls, you can then finally link it with .as_view():

urlpatterns = [
    path('/findData', DataListView.as_view())
]

Upvotes: 1

Related Questions