⚖️ Старый vs Новый — Урок 31
⚡ Главные отличия старого и нового
- Пагинация в APIView: из лекции — множественное наследование
APIView, PageNumberPagination; современный способ —pagination_classна Generic View - request.GET vs request.query_params: в DRF
request.query_paramsпредпочтительнееrequest.GET - Валидация sort_by: из лекции — без валидации; современный способ — белый список полей или
OrderingFilter - Фильтрация: из лекции — ручная через словарь; современный способ —
django-filterили DRFSearchFilter
1. Пагинация в APIView
Из лекции (работает, но не идиоматично)
# Множественное наследование
class BookListView(APIView, PageNumberPagination):
page_size = 5
def get(self, request):
books = Book.objects.all()
page_size = self.get_page_size(request)
self.page_size = page_size
results = self.paginate_queryset(
books, request, view=self
)
serializer = BookDetailSerializer(results, many=True)
return self.get_paginated_response(
serializer.data
)
def get_page_size(self, request):
page_size = request.query_params.get('page_size')
if page_size and page_size.isdigit():
return int(page_size)
return self.page_size
Современный способ (DRF 3.15+)
# Через pagination_class на Generic View
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 = BookDetailSerializer
pagination_class = BookPagination
Или глобально в settings.py:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
Итог: паттерн из лекции с множественным наследованием — учебный пример, он работает. В продакшн-коде предпочтительно использовать
pagination_class на Generic View или глобальную настройку.
2. request.GET vs request.query_params
Устаревший (Django-стиль)
# В чистом Django (FBV или CBV без DRF)
def book_list(request):
author = request.GET.get('author')
...
В DRF request — это обёрнутый объект, и request.GET работает, но это Django-стиль, не DRF-стиль.
Современный (DRF-стиль)
# В DRF APIView
class BookListView(APIView):
def get(self, request):
author = request.query_params.get('author')
...
request.query_params — предпочтительное имя в DRF. Семантически более явное.
3. Сортировка: без валидации vs с валидацией
Из лекции (без валидации)
class BookListView(APIView):
def get(self, request):
sort_by = request.query_params.get(
'sort_by', 'title'
)
sort_order = request.query_params.get(
'sort_order', 'asc'
)
books = Book.objects.all()
if sort_order == 'desc':
sort_by = f'-{sort_by}'
books = books.order_by(sort_by)
...
Проблема: клиент может передать произвольное поле, в т.ч. несуществующее — вызовет ошибку БД.
С белым списком (безопасно)
ALLOWED_SORT_FIELDS = {
'title', 'price', 'published_date', 'author'
}
class BookListView(APIView):
def get(self, request):
sort_by = request.query_params.get(
'sort_by', 'title'
)
sort_order = request.query_params.get(
'sort_order', 'asc'
)
# Валидация
if sort_by not in ALLOWED_SORT_FIELDS:
sort_by = 'title'
if sort_order == 'desc':
sort_by = f'-{sort_by}'
books = Book.objects.all().order_by(sort_by)
...
Или используйте OrderingFilter из DRF — декларативный и безопасный.
4. Ручная фильтрация vs django-filter
Из лекции (ручная)
class BookListView(APIView):
def get(self, request):
filters = {}
author = request.query_params.get('author')
if author:
filters['author'] = author
books = Book.objects.filter(**filters)
...
Подходит для простых случаев. При росте числа параметров код разрастается.
Декларативный (django-filter)
# pip install django-filter
import django_filters
from rest_framework import filters
from rest_framework.generics import ListAPIView
class BookFilter(django_filters.FilterSet):
author = django_filters.CharFilter(
field_name='author',
lookup_expr='icontains'
)
pub_year = django_filters.NumberFilter(
field_name='published_date',
lookup_expr='year'
)
class Meta:
model = Book
fields = ['author', 'pub_year']
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [
django_filters.rest_framework.DjangoFilterBackend,
filters.OrderingFilter,
]
filterset_class = BookFilter
ordering_fields = ['title', 'price']
⚠️ Проверить по документации: django-filter требует отдельной установки и настройки в
INSTALLED_APPS.