[Fixed]-Pagination with JsonResponse

13👍

Use Django’s Paginator.

from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
class ViewPaginatorMixin(object):
    min_limit = 1
    max_limit = 10

    def paginate(self, object_list, page=1, limit=10, **kwargs):
        try:
            page = int(page)
            if page < 1:
                page = 1
        except (TypeError, ValueError):
            page = 1

        try:
            limit = int(limit)
            if limit < self.min_limit:
                limit = self.min_limit
            if limit > self.max_limit:
                limit = self.max_limit
        except (ValueError, TypeError):
            limit = self.max_limit

        paginator = Paginator(object_list, limit)
        try:
            objects = paginator.page(page)
        except PageNotAnInteger:
            objects = paginator.page(1)
        except EmptyPage:
            objects = paginator.page(paginator.num_pages)
        data = {
            'previous_page': objects.has_previous() and objects.previous_page_number() or None,
            'next_page': objects.has_next() and objects.next_page_number() or None,
            'data': list(objects)
        }
        return data

Now, use the ViewPaginatorMixin to support pagination for View

class ResultQueryView(ViewPaginatorMixin, View):
    def get(self, request):
       // code
       serialized = ResourceSerializer(resources, many=True)
       return JsonResponse({"resources": self.paginate(serialized.data, page, limit)})

8👍

A simple solution could be to slice serialized.data just before building JsonResponse (and maybe even annotate the result with total n. of expected pages, that is math.ceil(len(serialized.data) / PAGE_SIZE)):

PAGE_SIZE = 10

start = page * PAGE_SIZE
stop = min(start + PAGE_SIZE, len(serialized.data))
#return JsonResponse({"resources": serialized.data})
return JsonResponse({"resources": serialized.data[start:stop]})

Test:

class FakeSerialized(object):
    def __init__(self):
        self.data = list(range(0,35))

serialized = FakeSerialized()
print('All data:', serialized.data)
PAGE_SIZE = 10

for page in range(0, 5):

    start = page * PAGE_SIZE
    stop = min(start + PAGE_SIZE, len(serialized.data))
    data = serialized.data[start:stop]

    print('Page %d:' % page, data)

Result:

$ python3 ./paginate.py
All data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
Page 0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Page 1: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Page 2: [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Page 3: [30, 31, 32, 33, 34]
Page 4: []

0👍

You can override a get_queryset() of a ListAPIView to return a queryset that is constructed according to your needs and then use the view’s built-in pagination:

from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination


class ResultQueryView(ListAPIView):
    serializer_class = ResourceSerializer
    # configure this according to your needs
    pagination_class = PageNumberPagination

    def get_queryset(self):
        resource_meta = self.request.GET.getlist("resource_meta")
        locations = self.request.GET.getlist("location")
        results = resource_query(resource_meta, locations)
        resource_ids = [r["_id"] for r in results['hits']['hits']]
        return Resource.objects.filter(internal_id__in=resource_ids))

0👍

This is just an example of how you could do it:

class nameClass(ListView):
     paginate_by = 25

    def get_paginate_by(self, queryset):
         return self.request.GET.get('pag_num', self.paginate_by)

    def get_context_data(self, **kwargs):
         context = super(nameClass, self).get_context_data(**kwargs)
         # we recover the number of pages
         context['pages'] = self.request.GET.get('pag_num', self.paginate_by)
         context['paginacion_personalizada'] = self.paginacion_personalizada
         return context

    def get_queryset(self):
         queryset = super(CorreccionSSPList, self).get_queryset()
         page_num = self.request.GET.get('pag_num', self.paginate_by)
         page = self.request.GET.get('page', 1)

         manager = MixinPaginator(queryset, page_num)
         self.paginator = manager.get_paginator(page)

         return queryset

maxin_paginator.py

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


class MixinPaginator:

    def __init__(self, objects, count):
        self.pages = Paginator(objects, count)



    def get_paginator(self, page):
        queryset = []
        try:
            queryset = self.pages.page(page)
        except PageNotAnInteger:
            queryset = self.pages.page(1)
        except EmptyPage:
            queryset = self.pages.page(1)

        return queryset

In your HTML:

                    <div class="col-xs-6 col-md-3 right">
                        <select id="input_num_pag" class="form-control" data-page='{{ pages }}'>
                            <option value="25">25</option>
                            <option value="50">50</option>
                            <option value="100">100</option>
                        </select>
                    </div>

0👍

I might be a bit late to answer this. but I did it using Django’s Paginator class

from django.core.paginator import Paginator


class ResultQueryView(View):
    def get(self, request):
        ....
        .... 
        max_records_required_per_page = 10
        queryset = Resource.objects.filter(internal_id__in=resource_ids)
        serializer = ResourceSerializer(queryset, many=True)
        p = Paginator(serializer.data, max_records_required_per_page)
        response = p.page(actual_value_of_page).object_list
        return JsonResponse({"resources": response})

Leave a comment