Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pagination with JsonResponse

I'd like to add pagination to my JsonResponse.

I'm currently using the django.http.JsonResponse to generate json from an elastic search API. I'd like to add a pagination feature to be included. My code is as follows:

class ResultQueryView(View):
    def get(self, request):
        resource_meta = request.GET.getlist("resource_meta")
        locations = request.GET.getlist("location")
        page = request.GET.get("page")
        logger.info("Got search query where resource_meta: {} and locations: {}".format(resource_meta, locations))
        results = resource_query(resource_meta, locations)
        resource_ids = [r["_id"] for r in results['hits']['hits']]
        resources = get_enriched_resources(request.user, Resource.objects.filter(internal_id__in=resource_ids))
        serialized = ResourceSerializer(resources, many=True)
        return JsonResponse({"resources": serialized.data})
like image 909
colonelrascals Avatar asked Feb 28 '18 18:02

colonelrascals


People also ask

How to do pagination in JSON?

Paginated JSON will usually have an object with links to the previous and next JSON pages. To get the previous page, you must send a request to the "prev" URL. To get to the next page, you must send a request to the "next" URL. This will deliver a new JSON with new results and new links for the next and previous pages.

Does pagination improve performance Django?

Additionally, switching to keyset pagination will improve the performance of page lookups and make them work in constant time. Django makes it easy to alter its default configuration, giving you the power to build a performant solution for pagination in Django.

What is the use of JsonResponse?

An HttpResponse subclass that helps to create a JSON-encoded response. It inherits most behavior from its superclass with some differences: Its default Content-Type header is set to application/json .

What is a JsonResponse?

JsonResponse is an HttpResponse subclass that helps to create a JSON-encoded response. Its default Content-Type header is set to application/json. The first parameter, data , should be a dict instance.


2 Answers

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)})
like image 141
sun_jara Avatar answered Sep 30 '22 12:09

sun_jara


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: []
like image 21
Mario Orlandi Avatar answered Sep 30 '22 13:09

Mario Orlandi