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

Ответ

В 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>

Ответ 18+ 🔞

Эй, ты, смотри сюда, а то я тебе сейчас про пагинацию в Django так расскажу, что ты обоссаешься от смеха, но зато запомнишь нахуй навсегда! Это ж не просто так, блядь, это целая наука, чтобы пользователи не сходили с ума, когда у тебя там тысяча записей в базе.

Так вот, в этом вашем Django есть, блядь, готовый класс Paginator. Он как раз для таких умников, как ты, который решил вывалить все сто пятьсот постов на одну страницу. Находится эта штука в django.core.paginator. Берёт он любой твой QuerySet (или даже просто список, если ты совсем извращенец) и режет его на аккуратные кусочки, как колбасу.

Как это вьюха делает, по шагам, чтобы даже дурак понял:

  1. Импортируешь этого Paginator-палача и тащишь из базы всё, что хочешь порезать.
  2. Создаёшь экземпляр, сука, этого пагинатора. Кидаешь ему в пасть твой QuerySet и говоришь, сколько штук на одной странице должно быть. Десять? Двадцать? Решай сам, пидор.
  3. Ловишь номер страницы, которую юзер хочет посмотреть. Он обычно в GET-параметре page приплывает, типа ?page=3.
  4. Просишь у пагинатора объект страницы через .get_page(). Это умный метод, он если ему какую-то хуйню в page подсунут (типа "абракадабра" или "-5"), он не сломается, а просто даст первую страницу. Красота, ёпта!

Смотри, как в 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. Спрашиваем у запроса: "Ну что, уважаемый, какую страничку тебе подсунуть?"
    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>

Вот и вся философия, блядь. Ничего сложного, но без этого — пиздец и бардак в интерфейсе. Делай так, и пользователи тебя не пошлют нахуй, листая твою бесконечную простыню из данных.