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

Ответ

Пагинация в Django позволяет разбивать большие наборы данных на отдельные страницы, что улучшает производительность загрузки и удобство использования (UX) для пользователя. Для этого используется встроенный модуль django.core.paginator.

Основные шаги реализации:

  1. Использование Paginator во View: В представлении (view) создается экземпляр Paginator, которому передается QuerySet объектов и количество элементов на страницу. Затем извлекается объект страницы (page_obj) на основе параметра запроса (обычно ?page=N).

    
    from django.core.paginator import Paginator
    from django.shortcuts import render
    from .models import Post # Предполагается модель Post

def post_list(request): posts = Post.objects.all().order_by('-created_at') # Получаем все посты, сортируем paginator = Paginator(posts, 10) # По 10 постов на страницу

page_number = request.GET.get('page') # Получаем номер текущей страницы из URL
page_obj = paginator.get_page(page_number) # Получаем объект страницы

return render(request, 'blog/post_list.html', {'page_obj': page_obj})
```
Метод `get_page()` безопасно обрабатывает некорректные номера страниц, возвращая первую страницу или последнюю, если номер слишком большой.
  1. Отображение пагинации в шаблоне: В шаблоне используется объект page_obj для итерации по элементам текущей страницы и для отображения ссылок на другие страницы.

    
    <!-- blog/post_list.html -->
    <h1>Список постов</h1>

{% for post in page_obj %}

{{ post.title }}

{{ post.content|truncatechars:150 }}

{% empty %}

Постов пока нет.

{% endfor %}

```
`page_obj` предоставляет удобные методы и атрибуты, такие как `has_previous`, `has_next`, `previous_page_number`, `next_page_number`, `number` (текущий номер страницы) и `paginator.num_pages` (общее количество страниц).

Пагинация для API (Django REST Framework): Для RESTful API в Django REST Framework (DRF) существуют специализированные классы пагинации, которые возвращают метаданные о пагинации вместе с данными:

  • PageNumberPagination: Разбивает данные на страницы по номеру страницы.
  • LimitOffsetPagination: Позволяет клиенту запрашивать определенное количество элементов, начиная со смещения.
  • CursorPagination: Использует "курсор" для определения следующей страницы, что эффективно для очень больших наборов данных и предотвращает проблемы с производительностью при изменении данных.

Пример настройки PageNumberPagination в settings.py для глобального применения:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

Или для конкретного ViewSet:

# views.py (DRF)
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from .models import Post
from .serializers import PostSerializer

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    pagination_class = StandardResultsSetPagination

Выбор метода пагинации зависит от требований к пользовательскому интерфейсу и API.