mirror of https://github.com/django/django.git
153 lines
4.7 KiB
Plaintext
153 lines
4.7 KiB
Plaintext
==========
|
|
Pagination
|
|
==========
|
|
|
|
Django provides high-level and low-level ways to help you manage paginated data
|
|
-- that is, data that's split across several pages, with "Previous/Next" links.
|
|
|
|
The ``Paginator`` class
|
|
=======================
|
|
|
|
Under the hood, all methods of pagination use the
|
|
:class:`~django.core.paginator.Paginator` class. It does all the heavy lifting
|
|
of actually splitting a ``QuerySet`` into parts and handing them over to other
|
|
components.
|
|
|
|
Example
|
|
=======
|
|
|
|
Give :class:`~django.core.paginator.Paginator` a list of objects, plus the
|
|
number of items you'd like to have on each page, and it gives you methods for
|
|
accessing the items for each page::
|
|
|
|
>>> from django.core.paginator import Paginator
|
|
>>> objects = ['john', 'paul', 'george', 'ringo']
|
|
>>> p = Paginator(objects, 2)
|
|
|
|
>>> p.count
|
|
4
|
|
>>> p.num_pages
|
|
2
|
|
>>> type(p.page_range)
|
|
<class 'range_iterator'>
|
|
>>> p.page_range
|
|
range(1, 3)
|
|
|
|
>>> page1 = p.page(1)
|
|
>>> page1
|
|
<Page 1 of 2>
|
|
>>> page1.object_list
|
|
['john', 'paul']
|
|
|
|
>>> page2 = p.page(2)
|
|
>>> page2.object_list
|
|
['george', 'ringo']
|
|
>>> page2.has_next()
|
|
False
|
|
>>> page2.has_previous()
|
|
True
|
|
>>> page2.has_other_pages()
|
|
True
|
|
>>> page2.next_page_number()
|
|
Traceback (most recent call last):
|
|
...
|
|
EmptyPage: That page contains no results
|
|
>>> page2.previous_page_number()
|
|
1
|
|
>>> page2.start_index() # The 1-based index of the first item on this page
|
|
3
|
|
>>> page2.end_index() # The 1-based index of the last item on this page
|
|
4
|
|
|
|
>>> p.page(0)
|
|
Traceback (most recent call last):
|
|
...
|
|
EmptyPage: That page number is less than 1
|
|
>>> p.page(3)
|
|
Traceback (most recent call last):
|
|
...
|
|
EmptyPage: That page contains no results
|
|
|
|
.. note::
|
|
|
|
Note that you can give ``Paginator`` a list/tuple, a Django ``QuerySet``,
|
|
or any other object with a ``count()`` or ``__len__()`` method. When
|
|
determining the number of objects contained in the passed object,
|
|
``Paginator`` will first try calling ``count()``, then fallback to using
|
|
``len()`` if the passed object has no ``count()`` method. This allows
|
|
objects such as Django's ``QuerySet`` to use a more efficient ``count()``
|
|
method when available.
|
|
|
|
Paginating a ``ListView``
|
|
=========================
|
|
|
|
:class:`django.views.generic.list.ListView` provides a builtin way to paginate
|
|
the displayed list. You can do this by adding
|
|
:attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` attribute to
|
|
your view class, for example::
|
|
|
|
from django.views.generic import ListView
|
|
|
|
from myapp.models import Contacts
|
|
|
|
class ContactsList(ListView):
|
|
paginate_by = 2
|
|
model = Contacts
|
|
|
|
The only thing your users will be missing is a way to navigate to the next or
|
|
previous page. To achieve this, add links to the next and previous page, like
|
|
shown in the below example ``list.html``.
|
|
|
|
.. _using-paginator-in-view:
|
|
|
|
Using ``Paginator`` in a view
|
|
=============================
|
|
|
|
Here's a slightly more complex example using
|
|
:class:`~django.core.paginator.Paginator` in a view to paginate a queryset. We
|
|
give both the view and the accompanying template to show how you can display
|
|
the results. This example assumes you have a ``Contacts`` model that has
|
|
already been imported.
|
|
|
|
The view function looks like this::
|
|
|
|
from django.core.paginator import Paginator
|
|
from django.shortcuts import render
|
|
|
|
def listing(request):
|
|
contact_list = Contacts.objects.all()
|
|
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
|
|
|
|
page = request.GET.get('page')
|
|
contacts = paginator.get_page(page)
|
|
return render(request, 'list.html', {'contacts': contacts})
|
|
|
|
In the template :file:`list.html`, you'll want to include navigation between
|
|
pages along with any interesting information from the objects themselves:
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% for contact in contacts %}
|
|
{# Each "contact" is a Contact model object. #}
|
|
{{ contact.full_name|upper }}<br>
|
|
...
|
|
{% endfor %}
|
|
|
|
<div class="pagination">
|
|
<span class="step-links">
|
|
{% if contacts.has_previous %}
|
|
<a href="?page=1">« first</a>
|
|
<a href="?page={{ contacts.previous_page_number }}">previous</a>
|
|
{% endif %}
|
|
|
|
<span class="current">
|
|
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
|
|
</span>
|
|
|
|
{% if contacts.has_next %}
|
|
<a href="?page={{ contacts.next_page_number }}">next</a>
|
|
<a href="?page={{ contacts.paginator.num_pages }}">last »</a>
|
|
{% endif %}
|
|
</span>
|
|
</div>
|