From 17557d068c43bd61cdc6c18caf250ffa469414a1 Mon Sep 17 00:00:00 2001 From: Thomas Chaumeny Date: Mon, 22 Sep 2014 18:46:43 +0200 Subject: [PATCH] Fixed #8408 -- Added ModelAdmin.show_full_result_count to avoid COUNT() query. Thanks lidaobing for the suggestion. --- django/contrib/admin/options.py | 1 + .../admin/templates/admin/change_list.html | 4 ++-- .../admin/templates/admin/search_form.html | 2 +- django/contrib/admin/views/main.py | 13 ++++++++++--- docs/ref/contrib/admin/index.txt | 13 +++++++++++++ docs/releases/1.8.txt | 4 ++++ tests/admin_views/admin.py | 1 + tests/admin_views/tests.py | 19 ++++++++++++++++++- 8 files changed, 50 insertions(+), 7 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index f7fce09ddc8..6edae7a5c51 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -110,6 +110,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): readonly_fields = () ordering = None view_on_site = True + show_full_result_count = True # Validation of ModelAdmin definitions # Old, deprecated style: diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html index ca0080e3be7..e99b1e0a6e5 100644 --- a/django/contrib/admin/templates/admin/change_list.html +++ b/django/contrib/admin/templates/admin/change_list.html @@ -87,9 +87,9 @@ {% endif %} {% block result_list %} - {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %} + {% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %} {% result_list cl %} - {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %} + {% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %} {% endblock %} {% block pagination %}{% pagination cl %}{% endblock %} diff --git a/django/contrib/admin/templates/admin/search_form.html b/django/contrib/admin/templates/admin/search_form.html index c9b626d18fd..4cc24604f78 100644 --- a/django/contrib/admin/templates/admin/search_form.html +++ b/django/contrib/admin/templates/admin/search_form.html @@ -6,7 +6,7 @@ {% if show_result_count %} - {% blocktrans count counter=cl.result_count %}{{ counter }} result{% plural %}{{ counter }} results{% endblocktrans %} ({% blocktrans with full_result_count=cl.full_result_count %}{{ full_result_count }} total{% endblocktrans %}) + {% blocktrans count counter=cl.result_count %}{{ counter }} result{% plural %}{{ counter }} results{% endblocktrans %} ({% if cl.show_full_result_count %}{% blocktrans with full_result_count=cl.full_result_count %}{{ full_result_count }} total{% endblocktrans %}{% else %}{% trans "Show all" %}{% endif %}) {% endif %} {% for pair in cl.params.items %} {% ifnotequal pair.0 search_var %}{% endifnotequal %} diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 1f42310f8e2..1fcc7746571 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -177,10 +177,13 @@ class ChangeList(object): # Perform a slight optimization: # full_result_count is equal to paginator.count if no filters # were applied - if self.get_filters_params() or self.params.get(SEARCH_VAR): - full_result_count = self.root_queryset.count() + if self.model_admin.show_full_result_count: + if self.get_filters_params() or self.params.get(SEARCH_VAR): + full_result_count = self.root_queryset.count() + else: + full_result_count = result_count else: - full_result_count = result_count + full_result_count = None can_show_all = result_count <= self.list_max_show_all multi_page = result_count > self.list_per_page @@ -194,6 +197,10 @@ class ChangeList(object): raise IncorrectLookupParameters self.result_count = result_count + self.show_full_result_count = self.model_admin.show_full_result_count + # Admin actions are shown if there is at least one entry + # or if entries are not counted because show_full_result_count is disabled + self.show_admin_actions = self.show_full_result_count or bool(full_result_count) self.full_result_count = full_result_count self.result_list = result_list self.can_show_all = can_show_all diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index ca55df3ce75..bf34fa47f14 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -1160,6 +1160,19 @@ subclass:: :meth:`ModelAdmin.get_search_results` to provide additional or alternate search behavior. +.. attribute:: ModelAdmin.show_full_result_count + + .. versionadded:: 1.8 + + Set ``show_full_result_count`` to control whether the full count of objects + should be displayed on a filtered admin page (e.g. ``99 results (103 total)``). + If this option is set to ``False``, a text like ``99 results (Show all)`` + is displayed instead. + + The default of ``show_full_result_count=True`` generates a query to perform + a full count on the table which can be expensive if the table contains a + large number of rows. + .. attribute:: ModelAdmin.view_on_site .. versionadded:: 1.7 diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index 5c28840c50b..c77b40a6a3c 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -72,6 +72,10 @@ Minor features ` in order to display a link to the front-end site. +* You can now specify :attr:`ModelAdmin.show_full_result_count + ` to control whether + or not the full count of objects should be displayed on a filtered admin page. + :mod:`django.contrib.auth` ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index 077d64b50d3..7caca29c7b4 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -327,6 +327,7 @@ class LanguageAdmin(admin.ModelAdmin): class RecommendationAdmin(admin.ModelAdmin): + show_full_result_count = False search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',) diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index c9b946ac5e5..88539d4684d 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -2474,11 +2474,28 @@ class AdminSearchTest(TestCase): """ Test presence of reset link in search bar ("1 result (_x total_)"). """ - response = self.client.get('/test_admin/admin/admin_views/person/?q=Gui') + # 1 query for session + 1 for fetching user + # + 1 for filtered result + 1 for filtered count + # + 1 for total count + with self.assertNumQueries(5): + response = self.client.get('/test_admin/admin/admin_views/person/?q=Gui') self.assertContains(response, """1 result (3 total)""", html=True) + def test_no_total_count(self): + """ + #8408 -- "Show all" should be displayed instead of the total count if + ModelAdmin.show_full_result_count is False. + """ + # 1 query for session + 1 for fetching user + # + 1 for filtered result + 1 for filtered count + with self.assertNumQueries(4): + response = self.client.get('/test_admin/admin/admin_views/recommendation/?q=bar') + self.assertContains(response, + """1 result (Show all)""", + html=True) + @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), ROOT_URLCONF="admin_views.urls")