Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework pagination extremely slow count

I turned pagination on in Django Rest framework and it appears to be incredibly slow. Count looks like the culprit, and is taking hundreds of milliseconds to return each time due to the millions of rows in the tables.

I am using postgresql as the database. Is there any way to not count the rows and still use pagination? The performance was fine before this was enabled if I manually filtered the queryset.

like image 647
Smills Avatar asked Jul 31 '15 07:07

Smills


People also ask

How to manage paginated data in Django with REST framework?

Django provides a few classes that help you manage paginated data – that is, data that’s split across several pages, with “Previous/Next” links. REST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data. The pagination API can support either:

What is pagination in Django?

— Django documentation REST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data. The pagination API can support either:

What are the pagination styles supported by REST API?

REST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data. The pagination API can support either: Pagination links that are provided as part of the content of the response.

How do I change the pagination style in the limitoffsetpagination?

The LimitOffsetPagination class includes a number of attributes that may be overridden to modify the pagination style. To set these attributes you should override the LimitOffsetPagination class, and then enable your custom pagination class as above.


1 Answers

The issue is, that the query used to count is the same potentially complex one as used to fetch the data. That's rather wasteful. PageNumberPagination uses Django's own Paginator internally.

To make the query for the count simpler override the paginator class DRF uses:

from django.core.paginator import Paginator
from django.utils.functional import cached_property
from rest_framework.pagination import PageNumberPagination

class FasterDjangoPaginator(Paginator):
    @cached_property
    def count(self):
        # only select 'id' for counting, much cheaper
        return self.object_list.values('id').count()


class FasterPageNumberPagination(PageNumberPagination):
    django_paginator_class = FasterDjangoPaginator
like image 152
Florian Avatar answered Sep 22 '22 21:09

Florian