Code

Ticket #11596: 11596.3.diff

File 11596.3.diff, 3.4 KB (added by SmileyChris, 3 years ago)

with docs

Line 
1diff --git a/django/core/paginator.py b/django/core/paginator.py
2index 495cdf2..479cb49 100644
3--- a/django/core/paginator.py
4+++ b/django/core/paginator.py
5@@ -1,4 +1,5 @@
6 from math import ceil
7+import collections
8 
9 class InvalidPage(Exception):
10     pass
11@@ -75,7 +76,7 @@ class Paginator(object):
12 
13 QuerySetPaginator = Paginator # For backwards-compatibility.
14 
15-class Page(object):
16+class Page(collections.Sequence):
17     def __init__(self, object_list, number, paginator):
18         self.object_list = object_list
19         self.number = number
20@@ -84,6 +85,14 @@ class Page(object):
21     def __repr__(self):
22         return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
23 
24+    def __len__(self):
25+        return len(self.object_list)
26+
27+    def __getitem__(self, index):
28+        # The object_list is converted to a list so that if it was a QuerySet
29+        # it won't be a database hit per __getitem__.
30+        return list(self.object_list)[index]
31+
32     def has_next(self):
33         return self.number < self.paginator.num_pages
34 
35diff --git a/docs/topics/pagination.txt b/docs/topics/pagination.txt
36index db776aa..197b61b 100644
37--- a/docs/topics/pagination.txt
38+++ b/docs/topics/pagination.txt
39@@ -104,7 +104,7 @@ The view function looks like this::
40 In the template :file:`list.html`, you'll want to include navigation between
41 pages along with any interesting information from the objects themselves::
42 
43-    {% for contact in contacts.object_list %}
44+    {% for contact in contacts %}
45         {# Each "contact" is a Contact model object. #}
46         {{ contact.full_name|upper }}<br />
47         ...
48@@ -126,6 +126,11 @@ pages along with any interesting information from the objects themselves::
49         </span>
50     </div>
51 
52+.. versionchanged:: 1.3
53+    Previously, you would need to use
54+    ``{% for contact in contacts.object_list %}``, since the ``Page``
55+    object was not iterable.
56+
57 
58 ``Paginator`` objects
59 =====================
60@@ -194,6 +199,7 @@ Attributes
61 
62     A 1-based range of page numbers, e.g., ``[1, 2, 3, 4]``.
63 
64+
65 ``InvalidPage`` exceptions
66 ==========================
67 
68@@ -221,6 +227,9 @@ them both with a simple ``except InvalidPage``.
69 You usually won't construct :class:`Pages <Page>` by hand -- you'll get them
70 using :meth:`Paginator.page`.
71 
72+.. versionadded:: 1.3
73+    A page acts like a sequence of :attr:`Page.object_list` when using
74+    ``len()`` or iterating it directly.
75 
76 Methods
77 -------
78diff --git a/tests/regressiontests/pagination_regress/tests.py b/tests/regressiontests/pagination_regress/tests.py
79index 28fe316..1cddd43 100644
80--- a/tests/regressiontests/pagination_regress/tests.py
81+++ b/tests/regressiontests/pagination_regress/tests.py
82@@ -154,3 +154,14 @@ class PaginatorTests(TestCase):
83         self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 0, False), 1, None)
84         self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 1, False), 1, None)
85         self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 2, False), 1, None)
86+
87+    def test_page_sequence(self):
88+        """
89+        Tests that a paginator page acts like a standard sequence.
90+        """
91+        eleven = 'abcdefghijk'
92+        page2 = Paginator(eleven, per_page=5, orphans=1).page(2)
93+        self.assertEqual(len(page2), 6)
94+        self.assertTrue('k' in page2)
95+        self.assertFalse('a' in page2)
96+        self.assertEqual(''.join(page2), 'fghijk')