• 3.1
  • 3.2
  • 5.0
  • Версия документации: 6.1

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

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

Объекты 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'>
>>> 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 список/кортеж, QuerySet Django или любой другой объект, который имеет методы count() или __len__(). Для определения количества объектов, содержащихся в переданном объекте, Paginator сначала попробует вызвать метод count(), затем, при его отсутствии, вызывает len(). Такой подход позволяет объектам, подобным QuerySet, более эффективно использовать метод 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. Чтобы пользователи могли перемещаться между страницами, добавьте в шаблон ссылки на следующую и предыдущую страницу следующим образом:

{% 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 подключен блок навигации по страницам:

Back to Top