Пагинация

Django предоставляет высокоуровневые и низкоуровневые способы управления постраничными данными - то есть данными, разделенными на несколько страниц, со ссылками «Предыдущая/Следующая».

Класс Paginator

Под капотом все методы пагинации используют класс Paginator. Он выполняет всю тяжелую работу по разбиению объекта QuerySet на объекты Page.

Пример

Дайте 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() метод, если он доступен.

Пагинация ListView

django.views.generic.list.ListView предоставляет встроенный способ постраничного просмотра отображаемого списка. Вы можете сделать это, добавив атрибут paginate_by к вашему классу представления, например:

from django.views.generic import ListView

from myapp.models import Contact

class ContactListView(ListView):
    paginate_by = 2
    model = Contact

Это ограничивает количество объектов на странице и добавляет paginator и page_obj к context. Чтобы пользователи могли перемещаться между страницами, добавьте ссылки на следующую и предыдущую страницу в ваш шаблон следующим образом:

{% for contact in page_obj %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}<br>
    ...
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; first</a>
            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">next</a>
            <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
        {% endif %}
    </span>
</div>

Использование Paginator в функции представления

Вот пример использования Paginator в функции представления для постраничного просмотра набора запросов:

from django.core.paginator import Paginator
from django.shortcuts import render

from myapp.models import Contact

def listing(request):
    contact_list = Contact.objects.all()
    paginator = Paginator(contact_list, 25) # Show 25 contacts per page.

    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'list.html', {'page_obj': page_obj})

В шаблоне list.html можно включить навигацию между страницами таким же образом, как и в шаблоне для ListView выше.

Вернуться на верх