📖 Теория — Урок 38
⚡ Ключевые концепции урока
- pagination_class — атрибут представления, задаёт класс пагинации
- PageNumberPagination — по номерам страниц (
?page=2&page_size=5) - LimitOffsetPagination — по смещению (
?limit=5&offset=10) - CursorPagination — курсорная, курсор зашифрован, самая безопасная
- DEFAULT_PAGINATION_CLASS — глобальная пагинация для всех представлений
- LOGGING — словарь в settings.py:
handlers,loggers,formatters - django.db.backends — логгер SQL-запросов, уровень DEBUG
Часть 1: Атрибут pagination_class
В Django REST Framework атрибут pagination_class позволяет настраивать механизм постраничной навигации (пагинации) для API. Пагинация помогает разделить результаты запросов на страницы, облегчая управление и отображение больших наборов данных.
Основное назначение
- Постраничная навигация: делит результаты запросов на страницы для удобного отображения
- Настройка размера страницы: позволяет задать количество элементов на странице
- Гибкость: поддерживает встроенные и кастомные классы пагинации
Встроенные классы пагинации
| Класс | Описание | Параметры запроса |
|---|---|---|
PageNumberPagination |
Навигация по номерам страниц и размеру страницы | ?page=2&page_size=5 |
LimitOffsetPagination |
Начальное смещение и лимит записей | ?limit=5&offset=10 |
CursorPagination |
Курсорная навигация — зашифрованный указатель позиции | ?cursor=bz0x... |
Часть 1а: PageNumberPagination
Пагинация с указанием номера страницы. Клиент запрашивает данные, указывая номер страницы (?page=2) и при необходимости размер страницы (?page_size=3).
Создание кастомного класса и подключение к представлению
# views.py
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
from .models import Book
from .serializers import BookSerializer
class BookPagination(PageNumberPagination):
page_size = 5 # количество элементов на странице по умолчанию
page_size_query_param = 'page_size' # клиент может указать размер через ?page_size=N
max_page_size = 100 # ограничение максимального размера страницы
class BookListCreateView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = BookPagination # подключаем наш класс
Атрибуты BookPagination
| Атрибут | Описание |
|---|---|
page_size |
Количество элементов на странице по умолчанию (здесь 5) |
page_size_query_param |
Параметр запроса для задания размера страницы клиентом |
max_page_size |
Максимально допустимый размер страницы (здесь 100) |
Примеры запросов
# Первая страница с размером по умолчанию (5 элементов)
GET http://127.0.0.1:8000/books/
# Вторая страница
GET http://127.0.0.1:8000/books/?page=2
# Вторая страница с 3 элементами на странице
GET http://127.0.0.1:8000/books/?page=2&page_size=3
Часть 1б: LimitOffsetPagination
Пагинация с указанием начального смещения (offset) и лимита (limit) количества записей. Удобна, когда нужна произвольная «прокрутка» по набору данных.
# views.py
from rest_framework.generics import ListAPIView
from rest_framework.pagination import LimitOffsetPagination
from .models import Book
from .serializers import BookSerializer
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = LimitOffsetPagination # используем напрямую
# Получить 5 книг, начиная с 11-й (пропустить первые 10)
GET http://127.0.0.1:8000/books/?limit=5&offset=10
limit— максимальное количество элементов на страницеoffset— начальное смещение от первого элемента (0-based)
Часть 1в: CursorPagination
CursorPagination — один из типов пагинации в DRF, который обеспечивает стабильную и безопасную навигацию по страницам данных. В отличие от других методов, использует курсоры для определения положения в наборе данных — особенно полезно при работе с динамически изменяющимися данными.
Основные преимущества
- Стабильная пагинация: порядок не «ломается», даже если данные добавляются или удаляются между запросами
- Безопасность: курсоры шифруются, что предотвращает манипуляции с параметрами
- Использование курсоров: курсор указывает конкретное положение в наборе данных
# views.py
from rest_framework.generics import ListAPIView
from rest_framework.pagination import CursorPagination
from .models import Book
from .serializers import BookSerializer
class BookCursorPagination(CursorPagination):
page_size = 5
ordering = 'published_date' # поле для определения позиции курсора
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = BookCursorPagination
Пример ответа API
GET http://127.0.0.1:8000/books/
{
"next": "http://127.0.0.1:8000/books/?cursor=bz0xJnA9MjAyMS0wMS0wMQ%3D%3D",
"previous": null,
"results": [
{
"id": 22,
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald",
"published_date": "1925-04-10",
"price": "10.23",
"is_bestseller": false
},
...
]
}
# Следующая страница через зашифрованный курсор
GET http://127.0.0.1:8000/books/?cursor=bz0xJnA9MjAyMS0wMS0wMQ%3D%3D
created_at. Если его нет в модели — создайте кастомный класс и укажите ordering явно. Без этого при глобальной настройке сервер упадёт с ошибкой.
Часть 2: Глобальная настройка пагинации
В DRF можно настроить глобальные параметры пагинации, которые будут применяться ко всем представлениям API. Это позволяет централизованно управлять поведением пагинации без дублирования настроек в каждом представлении.
Основные преимущества
- Централизованное управление: настройки задаются в одном месте в
settings.py - Консистентность: все представления следуют единым правилам пагинации
- Гибкость: можно переопределить глобальные параметры в конкретном представлении
PageNumberPagination — глобально
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 5, # размер страницы по умолчанию
}
LimitOffsetPagination — глобально
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 5, # лимит по умолчанию
}
CursorPagination — глобально (требует кастомного класса)
По умолчанию CursorPagination ищет поле created_at для создания курсора. Если такого поля нет — необходимо создать кастомный класс:
# pagination.py (отдельный файл в приложении)
from rest_framework.pagination import CursorPagination
class CustomCursorPagination(CursorPagination):
page_size = 5
ordering = 'published_date' # поле, которое реально существует в модели
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'first_app.pagination.CustomCursorPagination',
'PAGE_SIZE': 5,
}
Переопределение в конкретном представлении
# views.py — переопределение глобальной настройки для конкретного представления
class SpecialBookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = None # отключить пагинацию для этого представления
# или задать другой класс:
class SmallPageBookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = BookPagination # своя локальная настройка
Часть 3: Логирование запросов в базу данных
Логирование SQL-запросов помогает отлаживать и оптимизировать работу приложения: выявляет медленные запросы, анализирует поведение и отслеживает ошибки. В Django настройка логирования выполняется через словарь LOGGING в settings.py.
Основные концепции
- Логирование SQL-запросов: все SQL-запросы, выполняемые приложением, можно записывать для отладки и мониторинга
- Настройка логирования: стандартные механизмы Django через словарь
LOGGING - Анализ логов: обработка для выявления проблем с производительностью
Шаг 1: Включение отладочного режима
Для работы логгера SQL-запросов необходим DEBUG = True. В продакшн-среде SQL-запросы не логируются через django.db.backends при DEBUG = False — это ограничение Django.
# settings.py
DEBUG = True
Шаг 2: Настройка LOGGING
Словарь LOGGING имеет четыре ключевых секции:
| Секция | Назначение |
|---|---|
version |
Версия схемы конфигурации, всегда 1 |
disable_existing_loggers |
Если True — отключатся встроенные Django-логгеры. Почти всегда False |
handlers |
Куда записывать логи: консоль (StreamHandler) или файл (FileHandler) |
loggers |
Какие компоненты логировать и с каким уровнем |
Полная конфигурация LOGGING для SQL-запросов
# settings.py
import os
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'db.log'), # путь к файлу логов
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
}
Объяснение секций
| Элемент | Класс / значение | Описание |
|---|---|---|
handler console |
logging.StreamHandler |
Вывод логов в стандартный поток (консоль/терминал) |
handler file |
logging.FileHandler |
Запись логов в файл db.log |
logger django.db.backends |
level DEBUG |
Логирует все SQL-запросы при DEBUG = True |
db.log в корне проекта. Это позволяет отслеживать и анализировать выполнение запросов, выявлять N+1 проблемы и узкие места.
Уровни логирования
| Уровень | Числовое значение | Когда использовать |
|---|---|---|
DEBUG | 10 | Все события, включая SQL-запросы |
INFO | 20 | Информационные сообщения о работе |
WARNING | 30 | Предупреждения, но работа продолжается |
ERROR | 40 | Ошибки, требующие внимания |
CRITICAL | 50 | Критические ошибки, работа может остановиться |