Skip to content

Commit 159f260

Browse files
committed
Add encrypted admin w/"no count" pagination
Existing approaches to "no count" pagination do not seem to include support for pagination in the Django admin, so: - Subclass Django's core Paginator - override count - Subclass Django's contrib admin view ChangeList.get_results - Use len instead of count - Ruff fixes for try/except - Subclass Django's contrib ModelAdmin - override get_paginator - override get_changelist
1 parent ac265ce commit 159f260

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

django_mongodb_backend/admin.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from django.contrib import admin
2+
from django.contrib.admin.options import IncorrectLookupParameters
3+
from django.contrib.admin.views.main import ChangeList
4+
from django.core.paginator import InvalidPage, Paginator
5+
from django.utils.functional import cached_property
6+
7+
8+
class EncryptedPaginator(Paginator):
9+
@cached_property
10+
def count(self):
11+
return len(self.object_list)
12+
13+
14+
class EncryptedChangeList(ChangeList):
15+
def get_results(self, request):
16+
"""
17+
This is django.contrib.admin.views.main.ChangeList.get_results with
18+
a single modification to avoid COUNT queries.
19+
"""
20+
paginator = self.model_admin.get_paginator(request, self.queryset, self.list_per_page)
21+
result_count = paginator.count
22+
if self.model_admin.show_full_result_count:
23+
# Modification: avoid COUNT query by using len() on the root queryset
24+
full_result_count = len(self.root_queryset)
25+
else:
26+
full_result_count = None
27+
can_show_all = result_count <= self.list_max_show_all
28+
multi_page = result_count > self.list_per_page
29+
if (self.show_all and can_show_all) or not multi_page:
30+
result_list = self.queryset._clone()
31+
else:
32+
try:
33+
result_list = paginator.page(self.page_num).object_list
34+
except InvalidPage as err:
35+
raise IncorrectLookupParameters from err
36+
self.result_count = result_count
37+
self.show_full_result_count = self.model_admin.show_full_result_count
38+
self.show_admin_actions = not self.show_full_result_count or bool(full_result_count)
39+
self.full_result_count = full_result_count
40+
self.result_list = result_list
41+
self.can_show_all = can_show_all
42+
self.multi_page = multi_page
43+
self.paginator = paginator
44+
45+
46+
class EncryptedModelAdmin(admin.ModelAdmin):
47+
"""
48+
A ModelAdmin that uses EncryptedPaginator and EncryptedChangeList
49+
to avoid COUNT queries in the admin changelist.
50+
"""
51+
52+
def get_paginator(self, request, queryset, per_page):
53+
return EncryptedPaginator(queryset, per_page)
54+
55+
def get_changelist(self, request, **kwargs):
56+
return EncryptedChangeList

docs/ref/contrib/admin.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
=====
2+
Admin
3+
=====
4+
5+
Django MongoDB Backend supports the Django admin interface. To enable it, ensure
6+
that you have :ref:`specified the default pk field
7+
<specifying the-default-pk-field>` for the
8+
:class:`~django.contrib.admin.apps.AdminConfig` class as described in the
9+
:doc:`Getting Started </intro/configure>` guide.
10+
11+
``EncryptedModelAdmin``
12+
=======================
13+
14+
.. class:: EncryptedModelAdmin
15+
16+
.. versionadded:: 5.2.3
17+
18+
A :class:`~django.contrib.admin.ModelAdmin` subclass that supports models
19+
with encrypted fields. Use this class as a base class for your model's admin
20+
class to ensure that encrypted fields are handled correctly in the admin
21+
interface.
22+
23+
Register encrypted models with the Django admin using the
24+
``EncryptedModelAdmin`` as shown below::
25+
26+
# myapp/admin.py
27+
from django.contrib import admin
28+
from django_mongodb_backend.admin import EncryptedModelAdmin
29+
from .models import Patient
30+
31+
32+
@admin.register(Patient)
33+
class PatientAdmin(EncryptedModelAdmin):
34+
pass

0 commit comments

Comments
 (0)