Как реализовать пагинацию в Django

«Как реализовать пагинацию в Django» — вопрос из категории Django, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Django пагинация реализуется с помощью встроенного класса Paginator из модуля django.core.paginator. Он позволяет разбить большой QuerySet или любой другой итерируемый объект на страницы.

Процесс реализации во view:

  1. Импортировать Paginator и получить данные для пагинации.
  2. Создать экземпляр Paginator, передав ему QuerySet и количество элементов на странице.
  3. Получить номер текущей страницы из GET-параметра запроса (например, ?page=2).
  4. Получить объект страницы (Page) с помощью метода .get_page(), который безопасно обрабатывает некорректные номера.

Пример views.py:

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

def my_list_view(request):
    # 1. Получаем все объекты
    all_objects = MyModel.objects.all()

    # 2. Создаем пагинатор (10 объектов на страницу)
    paginator = Paginator(all_objects, 10)

    # 3. Получаем номер страницы из GET-параметра
    page_number = request.GET.get('page')

    # 4. Получаем объект страницы
    page_obj = paginator.get_page(page_number)

    return render(request, 'my_template.html', {'page_obj': page_obj})

Отображение в шаблоне (my_template.html):

В шаблоне объект page_obj предоставляет доступ к списку элементов на текущей странице и метаданным для навигации.

<!-- Отображение элементов текущей страницы -->
{% for item in page_obj %}
    <p>{{ item.name }}</p>
{% endfor %}

<!-- Навигация по страницам -->
<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; первая</a>
            <a href="?page={{ page_obj.previous_page_number }}">назад</a>
        {% endif %}

        <span class="current">
            Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}.
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">вперед</a>
            <a href="?page={{ page_obj.paginator.num_pages }}">последняя &raquo;</a>
        {% endif %}
    </span>
</div>