Skip to content

Instantly share code, notes, and snippets.

@pirate
Created September 12, 2024 03:59
Show Gist options
  • Save pirate/7877ada8370c516ce01b73c1385f018c to your computer and use it in GitHub Desktop.
Save pirate/7877ada8370c516ce01b73c1385f018c to your computer and use it in GitHub Desktop.
A faster version of the default Django Paginator
# This is an improved Django Paginator that makes Admin list view pages load much faster.
# You can tell if you need this if you see a big slow COUNT() query
# in the django_debug_toolbar SQL panel on every admin list view.
# It improves performance by avoiding running a potentially costly DISTINCT query to
# count total rows on every pageload. Instead, when possible (when there are no filters)
# it does a significantly simpler SELECT COUNT(*) tablename to get the total.
from django.core.paginator import Paginator
from django.utils.functional import cached_property
class AccelleratedPaginator(Paginator):
"""
Accellerated Pagniator ignores DISTINCT when counting total number of rows.
Speeds up SELECT Count(*) on Admin views by >20x.
https://hakibenita.com/optimizing-the-django-admin-paginator
"""
@cached_property
def count(self):
if self.object_list._has_filters():
# fallback to normal count method on filtered queryset
return super().count
# otherwise count total rows in a separate fast query
return self.object_list.model.objects.count()
# Alternative approach for PostgreSQL: fallback if count takes > 200ms
# from django.db import connection, transaction, OperationalError
# with transaction.atomic(), connection.cursor() as cursor:
# cursor.execute('SET LOCAL statement_timeout TO 200;')
# try:
# # try potentially slow count query, gets interrupted if it takes too long
# return super().count
# except OperationalError:
# # fallback to a faster but less accurate count (just returns total object of this type, without any costly filters)
# return self.object_list.model.objects.count()
# USAGE:
from django.contrib import admin
@admin.register(SomeModel)
class SomeModelAdmin(admin.ModelAdmin):
...
paginator = AccelleratedPaginator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment