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:44:47 +0100
commitdc95791e61750024a610b6c5cf4d32b7325fcb51 (patch)
treef76abd714d76d3f1640ce4626ed3b7755934bb19
parentbf35fb600637b020748d05b704a1c0257c7cb63a (diff)
[1.5.x] Fixed #19261 -- Delayed Queryset evaluation in paginators
Thanks trbs for the report and the patch. Backport of 1b307d6c8f from master.
-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 6b0b3542f8..084a29b77f 100644
--- a/django/core/paginator.py
+++ b/django/core/paginator.py
@@ -1,5 +1,8 @@
from math import ceil
+from django.utils import six
+
+
class InvalidPage(Exception):
pass
@@ -88,6 +91,8 @@ class Page(object):
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>",
+ ]
+ )