Fixed #11295: If ModelAdmin.queryset returns a filtered QS don't require a 2nd count call
Original patch rewritten, added tests and get_filters_params method for ChangeList class. Thanks Alex for the report.
This commit is contained in:
parent
e4ee3d8fca
commit
f07a5f0a21
|
@ -79,15 +79,23 @@ class ChangeList(object):
|
||||||
self.title = title % force_text(self.opts.verbose_name)
|
self.title = title % force_text(self.opts.verbose_name)
|
||||||
self.pk_attname = self.lookup_opts.pk.attname
|
self.pk_attname = self.lookup_opts.pk.attname
|
||||||
|
|
||||||
def get_filters(self, request):
|
def get_filters_params(self, params=None):
|
||||||
lookup_params = self.params.copy() # a dictionary of the query string
|
"""
|
||||||
use_distinct = False
|
Returns all params except IGNORED_PARAMS
|
||||||
|
"""
|
||||||
|
if not params:
|
||||||
|
params = self.params
|
||||||
|
lookup_params = params.copy() # a dictionary of the query string
|
||||||
# Remove all the parameters that are globally and systematically
|
# Remove all the parameters that are globally and systematically
|
||||||
# ignored.
|
# ignored.
|
||||||
for ignored in IGNORED_PARAMS:
|
for ignored in IGNORED_PARAMS:
|
||||||
if ignored in lookup_params:
|
if ignored in lookup_params:
|
||||||
del lookup_params[ignored]
|
del lookup_params[ignored]
|
||||||
|
return lookup_params
|
||||||
|
|
||||||
|
def get_filters(self, request):
|
||||||
|
lookup_params = self.get_filters_params()
|
||||||
|
use_distinct = False
|
||||||
|
|
||||||
# Normalize the types of keys
|
# Normalize the types of keys
|
||||||
for key, value in lookup_params.items():
|
for key, value in lookup_params.items():
|
||||||
|
@ -166,14 +174,13 @@ class ChangeList(object):
|
||||||
result_count = paginator.count
|
result_count = paginator.count
|
||||||
|
|
||||||
# Get the total number of objects, with no admin filters applied.
|
# Get the total number of objects, with no admin filters applied.
|
||||||
# Perform a slight optimization: Check to see whether any filters were
|
# Perform a slight optimization:
|
||||||
# given. If not, use paginator.hits to calculate the number of objects,
|
# full_result_count is equal to paginator.count if no filters
|
||||||
# because we've already done paginator.hits and the value is cached.
|
# were applied
|
||||||
if not self.query_set.query.where:
|
if self.get_filters_params():
|
||||||
full_result_count = result_count
|
|
||||||
else:
|
|
||||||
full_result_count = self.root_query_set.count()
|
full_result_count = self.root_query_set.count()
|
||||||
|
else:
|
||||||
|
full_result_count = result_count
|
||||||
can_show_all = result_count <= self.list_max_show_all
|
can_show_all = result_count <= self.list_max_show_all
|
||||||
multi_page = result_count > self.list_per_page
|
multi_page = result_count > self.list_per_page
|
||||||
|
|
||||||
|
|
|
@ -2537,6 +2537,34 @@ class AdminCustomQuerysetTest(TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertNotContains(response, 'Primary key = %s' % i)
|
self.assertNotContains(response, 'Primary key = %s' % i)
|
||||||
|
|
||||||
|
def test_changelist_view_count_queries(self):
|
||||||
|
#create 2 Person objects
|
||||||
|
Person.objects.create(name='person1', gender=1)
|
||||||
|
Person.objects.create(name='person2', gender=2)
|
||||||
|
|
||||||
|
# 4 queries are expected: 1 for the session, 1 for the user,
|
||||||
|
# 1 for the count and 1 for the objects on the page
|
||||||
|
with self.assertNumQueries(4):
|
||||||
|
resp = self.client.get('/test_admin/admin/admin_views/person/')
|
||||||
|
self.assertEqual(resp.context['selection_note'], '0 of 2 selected')
|
||||||
|
self.assertEqual(resp.context['selection_note_all'], 'All 2 selected')
|
||||||
|
with self.assertNumQueries(4):
|
||||||
|
extra = {'q': 'not_in_name'}
|
||||||
|
resp = self.client.get('/test_admin/admin/admin_views/person/', extra)
|
||||||
|
self.assertEqual(resp.context['selection_note'], '0 of 0 selected')
|
||||||
|
self.assertEqual(resp.context['selection_note_all'], 'All 0 selected')
|
||||||
|
with self.assertNumQueries(4):
|
||||||
|
extra = {'q': 'person'}
|
||||||
|
resp = self.client.get('/test_admin/admin/admin_views/person/', extra)
|
||||||
|
self.assertEqual(resp.context['selection_note'], '0 of 2 selected')
|
||||||
|
self.assertEqual(resp.context['selection_note_all'], 'All 2 selected')
|
||||||
|
# here one more count(*) query will run, because filters were applied
|
||||||
|
with self.assertNumQueries(5):
|
||||||
|
extra = {'gender__exact': '1'}
|
||||||
|
resp = self.client.get('/test_admin/admin/admin_views/person/', extra)
|
||||||
|
self.assertEqual(resp.context['selection_note'], '0 of 1 selected')
|
||||||
|
self.assertEqual(resp.context['selection_note_all'], '1 selected')
|
||||||
|
|
||||||
def test_change_view(self):
|
def test_change_view(self):
|
||||||
for i in self.pks:
|
for i in self.pks:
|
||||||
response = self.client.get('/test_admin/admin/admin_views/emptymodel/%s/' % i)
|
response = self.client.get('/test_admin/admin/admin_views/emptymodel/%s/' % i)
|
||||||
|
|
Loading…
Reference in New Issue