Fixed #19261 -- Delayed Queryset evaluation in paginators
Thanks trbs for the report and the patch.
This commit is contained in:
parent
aea8bf0662
commit
1b307d6c8f
|
@ -1,6 +1,9 @@
|
||||||
import collections
|
import collections
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
class InvalidPage(Exception):
|
class InvalidPage(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -89,6 +92,8 @@ class Page(collections.Sequence):
|
||||||
return len(self.object_list)
|
return len(self.object_list)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
|
if not isinstance(index, (slice,) + six.integer_types):
|
||||||
|
raise TypeError
|
||||||
# The object_list is converted to a list so that if it was a QuerySet
|
# The object_list is converted to a list so that if it was a QuerySet
|
||||||
# it won't be a database hit per __getitem__.
|
# it won't be a database hit per __getitem__.
|
||||||
return list(self.object_list)[index]
|
return list(self.object_list)[index]
|
||||||
|
|
|
@ -266,3 +266,25 @@ class ModelPaginationTests(TestCase):
|
||||||
self.assertEqual(1, p.previous_page_number())
|
self.assertEqual(1, p.previous_page_number())
|
||||||
self.assertEqual(6, p.start_index())
|
self.assertEqual(6, p.start_index())
|
||||||
self.assertEqual(9, p.end_index())
|
self.assertEqual(9, p.end_index())
|
||||||
|
|
||||||
|
def test_page_getitem(self):
|
||||||
|
"""
|
||||||
|
Tests proper behaviour of a paginator page __getitem__ (queryset
|
||||||
|
evaluation, slicing, exception raised).
|
||||||
|
"""
|
||||||
|
paginator = Paginator(Article.objects.all(), 5)
|
||||||
|
p = paginator.page(1)
|
||||||
|
|
||||||
|
# Make sure object_list queryset is not evaluated by an invalid __getitem__ call.
|
||||||
|
# (this happens from the template engine when using eg: {% page_obj.has_previous %})
|
||||||
|
self.assertIsNone(p.object_list._result_cache)
|
||||||
|
self.assertRaises(TypeError, lambda: p['has_previous'])
|
||||||
|
self.assertIsNone(p.object_list._result_cache)
|
||||||
|
|
||||||
|
# Make sure slicing the Page object with numbers and slice objects work.
|
||||||
|
self.assertEqual(p[0], Article.objects.get(headline='Article 1'))
|
||||||
|
self.assertQuerysetEqual(p[slice(2)], [
|
||||||
|
"<Article: Article 1>",
|
||||||
|
"<Article: Article 2>",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue