Last active
August 5, 2022 21:59
-
-
Save karthicraghupathi/48f97cd7a9bd618dfad436cbeb7506be to your computer and use it in GitHub Desktop.
A Django Admin Paginator For MariaDB With Many Many Rows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib import admin | |
from django.core.paginator import Paginator | |
from django.db import connection, transaction, OperationalError | |
from django.utils.functional import cached_property | |
class MariaDbInnoDbPaginator(Paginator): | |
""" | |
Paginator that enforces a 2 second timeout on the count operation. | |
If the operations times out, an approximate value is returned. | |
""" | |
@cached_property | |
def count(self): | |
with transaction.atomic(), connection.cursor() as cursor: | |
# for MySQL use max_execution_time; also in MySQL this is defined in milliseconds | |
# limit execution time to 2 seconds | |
cursor.execute("SET SESSION max_statement_time = 2") | |
try: | |
# let Django's paginator do it's work | |
return super().count | |
except OperationalError: | |
try: | |
# this must be a large table to let's approximate the total records | |
cursor.execute( | |
"SELECT TABLE_ROWS FROM information_schema.tables WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s", | |
(connection.settings_dict['NAME'], self.object_list.model._meta.db_table) | |
) | |
row = cursor.fetchone() | |
if row is not None: | |
return row[0] | |
else: | |
return 0 | |
except: | |
# return some arbitrary number if all else fails | |
return 9999999999 | |
class TunedAdmin(admin.ModelAdmin): | |
# set our paginator here | |
paginator = MariaDbInnoDbPaginator | |
# this is required to stop showing full counts when filtering results | |
show_full_result_count = False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You should now inherit from
TunedAdmin
instead ofadmin.ModelAdmin
in youradmin.py
.Setting the timeout and reading approximate record counts can be adapted to work with
other DBMS like MySql and PostgreSql.
For MySql:
max_execution_time
which should be defined in millisecondsFor PostgreSql:
SET LOCAL statement_timeout TO 200
SELECT reltuples FROM pg_class WHERE relname = %s
. Pass the table name here.References: