Fixes #11596 -- Make paginator.Page iterable
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16018 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
de5f07513b
commit
4fa9646716
|
@ -1,4 +1,5 @@
|
|||
from math import ceil
|
||||
import collections
|
||||
|
||||
class InvalidPage(Exception):
|
||||
pass
|
||||
|
@ -84,6 +85,44 @@ class Page(object):
|
|||
def __repr__(self):
|
||||
return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.object_list)
|
||||
|
||||
def __getitem__(self, index):
|
||||
# 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]
|
||||
|
||||
# The following four methods are only necessary for Python <2.6
|
||||
# compatibility (this class could just extend 2.6's collections.Sequence).
|
||||
|
||||
def __iter__(self):
|
||||
i = 0
|
||||
try:
|
||||
while True:
|
||||
v = self[i]
|
||||
yield v
|
||||
i += 1
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
def __contains__(self, value):
|
||||
for v in self:
|
||||
if v == value:
|
||||
return True
|
||||
return False
|
||||
|
||||
def index(self, value):
|
||||
for i, v in enumerate(self):
|
||||
if v == value:
|
||||
return i
|
||||
raise ValueError
|
||||
|
||||
def count(self, value):
|
||||
return sum([1 for v in self if v == value])
|
||||
|
||||
# End of compatibility methods.
|
||||
|
||||
def has_next(self):
|
||||
return self.number < self.paginator.num_pages
|
||||
|
||||
|
|
|
@ -81,22 +81,20 @@ show how you can display the results. This example assumes you have a
|
|||
|
||||
The view function looks like this::
|
||||
|
||||
from django.core.paginator import Paginator, InvalidPage, EmptyPage
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
|
||||
def listing(request):
|
||||
contact_list = Contacts.objects.all()
|
||||
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
|
||||
|
||||
# Make sure page request is an int. If not, deliver first page.
|
||||
try:
|
||||
page = int(request.GET.get('page', '1'))
|
||||
except ValueError:
|
||||
page = 1
|
||||
|
||||
# If page request (9999) is out of range, deliver last page of results.
|
||||
page = request.GET.get('page')
|
||||
try:
|
||||
contacts = paginator.page(page)
|
||||
except (EmptyPage, InvalidPage):
|
||||
except PageNotAnInteger:
|
||||
# If page is not an integer, deliver first page.
|
||||
contacts = paginator.page(1)
|
||||
except EmptyPage:
|
||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||
contacts = paginator.page(paginator.num_pages)
|
||||
|
||||
return render_to_response('list.html', {"contacts": contacts})
|
||||
|
@ -104,7 +102,7 @@ The view function looks like this::
|
|||
In the template :file:`list.html`, you'll want to include navigation between
|
||||
pages along with any interesting information from the objects themselves::
|
||||
|
||||
{% for contact in contacts.object_list %}
|
||||
{% for contact in contacts %}
|
||||
{# Each "contact" is a Contact model object. #}
|
||||
{{ contact.full_name|upper }}<br />
|
||||
...
|
||||
|
@ -126,6 +124,11 @@ pages along with any interesting information from the objects themselves::
|
|||
</span>
|
||||
</div>
|
||||
|
||||
.. versionchanged:: 1.4
|
||||
Previously, you would need to use
|
||||
``{% for contact in contacts.object_list %}``, since the ``Page``
|
||||
object was not iterable.
|
||||
|
||||
|
||||
``Paginator`` objects
|
||||
=====================
|
||||
|
@ -194,6 +197,7 @@ Attributes
|
|||
|
||||
A 1-based range of page numbers, e.g., ``[1, 2, 3, 4]``.
|
||||
|
||||
|
||||
``InvalidPage`` exceptions
|
||||
==========================
|
||||
|
||||
|
@ -221,6 +225,9 @@ them both with a simple ``except InvalidPage``.
|
|||
You usually won't construct :class:`Pages <Page>` by hand -- you'll get them
|
||||
using :meth:`Paginator.page`.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
A page acts like a sequence of :attr:`Page.object_list` when using
|
||||
``len()`` or iterating it directly.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
|
|
@ -154,3 +154,15 @@ class PaginatorTests(TestCase):
|
|||
self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 0, False), 1, None)
|
||||
self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 1, False), 1, None)
|
||||
self.assertRaises(EmptyPage, self.check_indexes, ([], 4, 2, False), 1, None)
|
||||
|
||||
def test_page_sequence(self):
|
||||
"""
|
||||
Tests that a paginator page acts like a standard sequence.
|
||||
"""
|
||||
eleven = 'abcdefghijk'
|
||||
page2 = Paginator(eleven, per_page=5, orphans=1).page(2)
|
||||
self.assertEqual(len(page2), 6)
|
||||
self.assertTrue('k' in page2)
|
||||
self.assertFalse('a' in page2)
|
||||
self.assertEqual(''.join(page2), 'fghijk')
|
||||
self.assertEqual(''.join(reversed(page2)), 'kjihgf')
|
||||
|
|
Loading…
Reference in New Issue