⚖️ Старый vs Новый — Урок 38
⚡ Главные отличия
- Ручная пагинация в APIView →
pagination_classв Generic Views - Устаревший DRF-формат LOGGING с
'%(levelname)s'→'style': '{'в Django 3.2+ - Глобальная пагинация без кастомного класса → всегда кастомный класс для CursorPagination
1. Ручная пагинация (из лекции) → pagination_class (современно)
Из лекции (старое) — ручная пагинация в APIView
# views.py — ручная пагинация через Paginator (Django встроенный)
from django.core.paginator import Paginator
from rest_framework.views import APIView
from rest_framework.response import Response
class BookListView(APIView):
def get(self, request):
books = Book.objects.all()
paginator = Paginator(books, 5) # 5 на страницу
page_number = request.query_params.get('page', 1)
page_obj = paginator.get_page(page_number)
serializer = BookSerializer(page_obj, many=True)
return Response({
'count': paginator.count,
'results': serializer.data,
})
Современное — pagination_class в Generic Views (DRF 3.x)
# views.py — DRF встроенная пагинация
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
class BookPagination(PageNumberPagination):
page_size = 5
page_size_query_param = 'page_size'
max_page_size = 100
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = BookPagination
# next/previous/count — автоматически в ответе
Преимущество: DRF автоматически добавляет
count, next, previous в ответ. Ручная пагинация требует делать это вручную и не совместима с Browsable API.
2. Формат LOGGING (из лекции) → современный Django 3.2+
Из лекции (старый стиль форматтера — %-стиль)
# settings.py — %-стиль форматтера (Python 2 / ранний Django)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(message)s',
# style не указан — по умолчанию '%'
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'db.log', # относительный путь — плохая практика
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
},
},
}
Современное (Django 3.2+ / Django 5.x)
# settings.py — {}-стиль форматтера + абсолютные пути
import os
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[{asctime}] {levelname} {name} — {message}',
'style': '{', # явно указываем стиль
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs', 'db_logs.log'), # абсолютный путь!
'formatter': 'verbose',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console', 'file'],
'level': 'DEBUG',
'propagate': False, # не дублировать вверх по иерархии
},
},
}
3. CursorPagination без кастомного класса → с кастомным
Из лекции (упрощённо — работает только если в модели есть created_at)
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 5,
}
# Если в модели нет created_at — AttributeError при первом запросе!
Современная практика — всегда кастомный класс для CursorPagination
# pagination.py
from rest_framework.pagination import CursorPagination
class CustomCursorPagination(CursorPagination):
page_size = 6
ordering = 'published_date' # укажите поле, которое реально есть в модели
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'first_app.pagination.CustomCursorPagination',
'PAGE_SIZE': 6,
}
Правило: никогда не используйте
'rest_framework.pagination.CursorPagination' напрямую в DEFAULT_PAGINATION_CLASS без проверки наличия поля created_at во всех моделях. Создайте кастомный класс — это явно и безопасно.
4. disable_existing_loggers: True vs False
Опасный вариант (из старых примеров в интернете)
LOGGING = {
'version': 1,
'disable_existing_loggers': True, # ОПАСНО — отключит ВСЕ встроенные логгеры Django!
...
}
Правильный вариант
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # встроенные логгеры Django продолжат работу
...
}
Почему важно: при
True отключаются django.request, django.security, django.server — вы перестанёте видеть критические ошибки и предупреждения безопасности. Почти всегда нужно False.