Пагинация¶
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)
<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()
. Это позволяет таким объектам, как QuerySet
Django, использовать более эффективный count()
метод, если он доступен.
Использование Paginator
в представлении¶
Вот немного более сложный пример использования Paginator
в представлении для постраничного вывода набора запросов. Мы приводим и представление, и сопутствующий шаблон, чтобы показать, как можно отобразить результаты. В этом примере предполагается, что у вас есть модель Contacts
, которая уже была импортирована.
Функция просмотра выглядит следующим образом:
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})
В шаблоне 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=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>
Paginator
объекты¶
Класс Paginator
имеет этот конструктор:
-
class
Paginator
(object_list, per_page, orphans=0, allow_empty_first_page=True)[исходный код]¶
Необходимые аргументы¶
object_list
Список, кортеж,
QuerySet
или другой разрезаемый объект с методомcount()
или__len__()
. Для последовательной пагинацииQuerySet
должны быть упорядочены, например, с помощьюorder_by()
оговорки или по умолчаниюordering
в модели.Проблемы с производительностью при пагинации больших
QuerySet
sЕсли вы используете
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.
get_page
(number)[исходный код]¶ Возвращает объект
Page
с заданным индексом, основанным на 1, при этом также обрабатывает номера страниц вне диапазона и недопустимые номера страниц.Если страница не имеет номера, возвращается первая страница. Если номер страницы отрицателен или больше числа страниц, возвращается последняя страница.
Он вызывает исключение (
EmptyPage
), только если вы указалиPaginator(..., allow_empty_first_page=False)
иobject_list
пуст.
-
Paginator.
page
(number)[исходный код]¶ Возвращает объект
Page
с заданным индексом, основанным на 1. Вызывает сообщение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, например, дающий
[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)[исходный код]¶ Страница ведет себя как последовательность
Page.object_list
при использованииlen()
или прямой итерации.
Методы¶
-
Page.
has_next
()[исходный код]¶ Возвращает
True
, если есть следующая страница.
-
Page.
has_previous
()[исходный код]¶ Возвращает
True
, если существует предыдущая страница.
-
Page.
has_other_pages
()[исходный код]¶ Возвращает
True
, если есть следующая или предыдущая страница.
-
Page.
next_page_number
()[исходный код]¶ Возвращает номер следующей страницы. Вызывает
InvalidPage
, если следующая страница не существует.
-
Page.
previous_page_number
()[исходный код]¶ Возвращает номер предыдущей страницы. Вызывает
InvalidPage
, если предыдущая страница не существует.
-
Page.
start_index
()[исходный код]¶ Возвращает основанный на 1 индекс первого объекта на странице, относительно всех объектов в списке пагинатора. Например, при пагинации списка из 5 объектов с 2 объектами на странице, на второй странице
start_index()
вернет3
.
-
Page.
end_index
()[исходный код]¶ Возвращает основанный на 1 индекс последнего объекта на странице, относительно всех объектов в списке пагинатора. Например, при пагинации списка из 5 объектов с 2 объектами на странице, на второй странице
end_index()
вернет4
.