diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index f7fce09ddc..6edae7a5c5 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 ca0080e3be..e99b1e0a6e 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 c9b626d18f..4cc24604f7 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 1f42310f8e..1fcc774657 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 ca55df3ce7..bf34fa47f1 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 5c28840c50..c77b40a6a3 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 077d64b50d..7caca29c7b 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 c9b946ac5e..88539d4684 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")