summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2012-11-09 19:37:50 +0100
committerClaude Paroz <claude@2xlibre.net>2012-11-09 19:41:57 +0100
commit1b307d6c8fe9a897da2daa189b7d5f59120e4410 (patch)
tree27d1c88aeafcbc7891fc05c46b5e1b1a7302bfcd
parentaea8bf06620c931f7b1e7d991497d593b91f71c9 (diff)
Fixed #19261 -- Delayed Queryset evaluation in paginators
Thanks trbs for the report and the patch.
-rw-r--r--django/core/paginator.py5
-rw-r--r--tests/regressiontests/pagination/tests.py22
2 files changed, 27 insertions, 0 deletions
diff --git a/django/core/paginator.py b/django/core/paginator.py
index 6c502ae5f3..d22e16c452 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -1,6 +1,9 @@
import collections
from math import ceil
+from django.utils import six
+
+
class InvalidPage(Exception):
pass
@@ -89,6 +92,8 @@ class Page(collections.Sequence):
return len(self.object_list)
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
# it won't be a database hit per __getitem__.
return list(self.object_list)[index]
diff --git a/tests/regressiontests/pagination/tests.py b/tests/regressiontests/pagination/tests.py
index a49f9b8fa1..63ccd8f61c 100644
--- a/tests/regressiontests/pagination/tests.py
+++ b/tests/regressiontests/pagination/tests.py
@@ -266,3 +266,25 @@ class ModelPaginationTests(TestCase):
self.assertEqual(1, p.previous_page_number())
self.assertEqual(6, p.start_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>",
+ ]
+ )