Пейджирование
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 >>> type(p.page_range) # `<type 'rangeiterator'>` in Python 2. <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
Примечание
Обратите внимание, что вы можете передать Paginator список/кортеж, Django QuerySet, или любой другой объект с методом count() или __len__(). При определении количества объектов в переданном объекте, Paginator сначала попытается вызвать count(), а затем использует len(), если у переданного объекта нет метода count(). Это позволяет объектам, таким как Django QuerySet, использовать более эффективный метод count() при его наличии.
Использование Paginator в представлении
Вот немного более сложный пример использования Paginator в представлении для пейджирования набора запросов. Мы предоставим как представление, так и соответствующий шаблон, чтобы показать, как отображать результаты. Этот пример предполагает, что модель Contacts уже импортирована.
Функция представления выглядит так:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
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')
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(request, '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>
Paginator объекты
Класс Paginator имеет такой конструктор:
-
class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)[source]
Необходимые аргументы
-
object_list -
Список, кортеж,
QuerySet, или другой объект с нарезкой (sliceable) и методомcount()или__len__(). Для согласованного пейджирования объекты должны быть упорядочены, например, с помощью условияorder_by()или с помощью параметраorderingв модели.Проблемы производительности при пейджировании больших
QuerySetЕсли вы используете
QuerySetс очень большим количеством элементов, запрос высоких номеров страниц может быть медленным на некоторых базах данных, потому что результат запросаLIMIT/OFFSETдолжен подсчитать количествоOFFSETзаписей, что занимает больше времени по мере увеличения номера страницы. -
per_page - Максимальное количество элементов на странице, не включая лишние (см. необязательный аргумент
orphansниже).
Необязательные аргументы
-
orphans - Используйте, когда вы не хотите иметь последнюю страницу с очень малым количеством элементов. Если последняя страница обычно содержит количество элементов меньше или равно
orphans, эти элементы будут добавлены к предыдущей странице (которая станет последней), а не оставаться на отдельной странице. Например, с 23 элементами,per_page=10, иorphans=3, будет две страницы: первая страница с 10 элементами и вторая (последняя) страница с 13 элементами.orphansпо умолчанию равен нулю, что означает, что страницы никогда не объединяются, и последняя страница может содержать один элемент. -
allow_empty_first_page - Разрешено ли пустая первая страница. Если
Falseиobject_listпустые, будет поднято исключениеEmptyPage.
Методы
-
Paginator.page(number)[source] -
Возвращает объект
Pageс заданным индексом (с 1). Поднимает исключениеInvalidPage, если заданного номера страницы не существует.
Атрибуты
-
Paginator.count -
Общее количество объектов на всех страницах.
Примечание
При определении количества объектов в
object_list,Paginatorсначала попытается вызватьobject_list.count(). Еслиobject_listне имеет методаcount(),Paginatorобратится кlen(object_list). Это позволяет объектам, таким как DjangoQuerySet, использовать более эффективный методcount()при его наличии.
-
Paginator.num_pages -
Общее количество страниц.
-
Paginator.page_range -
Итератор диапазона номеров страниц (с 1), например, возвращающий
[1, 2, 3, 4].Изменено в Django 1.9:В старых версиях
page_rangeвозвращал список вместо итератора.
InvalidPage исключения
-
exception InvalidPage[source] -
Базовый класс исключений, которые поднимаются, когда пейджировщику передается неверный номер страницы.
Метод Paginator.page() поднимает исключение, если запрошенная страница неверна (т.е. не является целым числом) или не содержит объектов. Как правило, достаточно перехватить исключение InvalidPage, но если вам нужна более подробная информация, вы можете перехватить любое из следующих исключений:
-
exception PageNotAnInteger[source] -
Поднимается, когда
page()получает значение, которое не является целым числом.
-
exception EmptyPage[source] -
Поднимается, когда
page()получает допустимое значение, но на этой странице нет объектов.
Оба исключения являются подклассами InvalidPage, поэтому вы можете обработать их оба с помощью простого except InvalidPage.
Page объекты
Обычно вы не будете создавать объекты Page вручную - вы получите их с помощью Paginator.page().
-
class Page(object_list, number, paginator)[source] -
Страница ведет себя как последовательность
Page.object_listпри использованииlen()или прямом итерировании.
Методы
-
Page.has_next()[source] -
Возвращает
True, если есть следующая страница.
-
Page.has_previous()[source] -
Возвращает
True, если есть предыдущая страница.
-
Page.has_other_pages()[source] -
Возвращает
True, если есть следующая или предыдущая страница.
-
Page.next_page_number()[source] -
Возвращает номер следующей страницы. Поднимает исключение
InvalidPage, если следующая страница не существует.
-
Page.previous_page_number()[source] -
Возвращает номер предыдущей страницы. Поднимает исключение
InvalidPage, если предыдущая страница не существует.
-
Page.start_index()[source] -
Возвращает индекс первого объекта на странице, отсчитываемый с 1, относительно всего списка объектов в пагинаторе. Например, при разбиении списка из 5 объектов на страницы по 2 объекта на странице,
start_index()второй страницы вернёт3.
-
Page.end_index()[source] -
Возвращает индекс последнего объекта на странице, отсчитываемый с 1, относительно всего списка объектов в пагинаторе. Например, при разбиении списка из 5 объектов на страницы по 2 объекта на странице,
end_index()второй страницы вернёт4.
Атрибуты
-
Page.object_list -
Список объектов на этой странице.
-
Page.number -
Номер страницы (отсчитывается с 1) для этой страницы.
-
Page.paginator -
Соответствующий объект
Paginator.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.10/topics/pagination/