Постраничный вывод

Django предоставляет несколько классов, которые помогают реализовать постраничный вывод данных, т.е. данных, распределённых на несколько страниц с ссылками «Предыдущая/Следующая». Эти классы располагаются в django/core/paginator.py.

Пример

Передайте в класс Paginator список объектов и количество элементов, которое надо отображать на странице. Класс предоставит методы для доступа к элементам каждой страницы:

>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)

>>> p.count
4
>>> p.num_pages
2
>>> p.page_range
[1, 2]

>>> 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()
3
>>> 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

Примечание

Следует отметить, что вы можете передать классу Paginator список/кортеж, QuerySet Django или любой другой объект, который имеет методы count() или __len__(). Для определения количества объектов, содержащихся в переданном объекте, Paginator сначала попробует вызвать метод count(), затем, при его отсутствии, вызывает len(). Такой подход позволяет объектам, подобным QuerySet, более эффективно использовать метод count() при его наличии.

Использование Paginator в представлении

Здесь приведён более сложный пример использования класса Paginator в представлении для постраничного вывода результатов запроса. Мы предоставили представление и его шаблон, чтобы показать, как вы можете отображать результаты. Данный пример предполагает наличие у вас модели Contacts, которая уже была импортирована.

Функция представления может выглядеть так:

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

    page = request.GET.get('page')
    try:
        contacts = paginator.page(page)
    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})

В шаблоне list.html подключен блок навигации по страницам:

{% 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={{ 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>
        {% endif %}
    </span>
</div>
Изменено в Django 1.4: Previously, you would need to use {% for contact in contacts.object_list %}, since the Page object was not iterable.

Объекты Paginator

У класса Paginator есть конструктор:

class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)

Обязательные аргументы

object_list
Список, кортеж, Django QuerySet, или другой контейнер, у которого есть метод count() или``__len__()``.
per_page
Максимальное количество элементов на странице, без учёта остатка (см. далее необязательный аргумент``orphans``).

Необязательные аргументы

orphans
Минимальное количество элементов на последней странице, по умолчанию, ноль. Используйте, когда нежелательно отображать последнюю страницу почти пустой. Если последняя страница будет сделать элементов менее и равное orphans, то эти элементы будут добавлены к предыдущей странице (которая станет последней). Например, для 23 элементов, per_page=10``и ``orphans=3, будет выдано две страницы; первая страница будет содержать 10 элементов, а вторая (и последняя) — 13.
allow_empty_first_page
Позволять или нет первой странице быть пустой. Если указан False и object_list пустой, то будет вызвано исключение EmptyPage.

Методы

Paginator.page(number)

Возвращает объект Page по переданному индексу (начинается с единицы). Вызывает исключение InvalidPage, если указанная страница не существует.

Атрибуты

Paginator.count

Общее количество объектов, распределенных по всем страницам.

Примечание

При определении количества объектов, содержащихся в object_list, Paginator сначала пробует вызвать object_list.count(). Если у object_list нет метода count(), то Paginator попробует вызвать len(object_list). Такой подход позволяет объектам, подобным QuerySet Django, более эффективно использовать метод count() при его наличии.

Paginator.num_pages

Общее количество страниц.

Paginator.page_range

Диапазон номеров страниц, начинающийся с единицы, т.е., [1, 2, 3, 4].

InvalidPage исключения

exception InvalidPage

Базовый класс для исключений, которые вызываются когда происходит запрос страницы по несуществующему номеру.

Метод Paginator.page() вызывает исключение, если номер запрошенной страницы является неправильным (т.е., не представлен целым числом) или не содержит объектов. В общем случае, достаточно обрабатывать исключение InvalidPage, но если вам требуется более тонкий контроль, вы можете отрабатывать следующие исключения:

exception PageNotAnInteger

Вызывается, если page() получает значение, которое не является целым числом.

exception EmptyPage

Вызывается, если page() получает правильное значение, но для указанной страницы нет объектов.

Эти исключения являются потомками класса InvalidPage, таким образом, вы можете обрабатывать их с помощью простого except InvalidPage.

Объекты Page

Обычно создавать объекты Page вручную не требуется, так как вы получаете их с помощью метода Paginator.page().

class Page(object_list, number, paginator)
Добавлено в Django 1.4: A page acts like a sequence of Page.object_list when using len() or iterating it directly.

Методы

Page.has_next()

Возвращает True, если следующая страница существует.

Page.has_previous()

Возвращает True, если предыдущая страница существует.

Page.has_other_pages()

Возвращает True, если существует следующая или предыдущая страница.

Page.next_page_number()

Возвращает номер следующей страницы. Следует отметить, что «интеллекта» здесь нет и номер будет возвращён даже в случае, когда следующая страница не существует.

Page.previous_page_number()

Возвращает номер предыдущей страницы. Следует отметить, что «интеллекта» здесь нет и номер будет возвращён даже в случае, когда предыдущая страница не существует.

Page.start_index()

Возвращает индекс (начинается с единицы) первого объекта на странице относительно списка всех объектов. Например, для списка из пяти объектов при отображении двух объектов на странице, то для второй страницы метод start_index() вернёт 3.

Page.end_index()

Возвращает индекс (начинается с единицы) последнего объекта на странице относительно списка всех объектов. Например, для списка из пяти объектов при отображении двух объектов на странице, то для второй страницы метод end_index() вернёт 4.

Атрибуты

Page.object_list

Список объектов текущей страницы.

Page.number

Номер (начинается с единицы) текущей страницы.

Page.paginator

Соответствующий объект Paginator.