🐛 Типичные ошибки практикума 8
⚡ Топ-5 ошибок
- Забыть
'django_filters'вINSTALLED_APPS—DjangoFilterBackendне работает - Не вызвать
.as_view()при регистрации Generic View вurlpatterns - Спутать порядок аргументов
router.register(r'url-prefix', ViewSetClass) - Использовать Generic View вместо ViewSet для простых моделей (лишний код)
- Не установить пакет
pip install django-filterперед использованием
Ошибка 1: django_filters не в INSTALLED_APPS
Симптом: AttributeError: module 'django_filters' has no attribute 'rest_framework' или фильтрация просто не работает.
# ОШИБКА: django_filters не добавлен
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'rest_framework',
# 'django_filters' — забыли!
]
# ПРАВИЛЬНО:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'rest_framework',
'django_filters', # обязательно!
]
Причина: django_filters — отдельный пакет, не входящий в DRF. Его нужно и установить (pip install django-filter), и добавить в приложения.
Ошибка 2: забыть .as_view() для Generic Views
Симптом: TypeError: view must be a callable or a list/tuple
# ОШИБКА: нет .as_view()
urlpatterns = [
path('products/', ProductListCreateView), # ошибка!
path('products/<int:pk>/', ProductDetailView), # ошибка!
]
# ПРАВИЛЬНО:
urlpatterns = [
path('products/', ProductListCreateView.as_view()),
path('products/<int:pk>/', ProductDetailView.as_view()),
]
Причина: urlpatterns ожидает callable (функцию). Класс-представление нужно превратить в вызываемую функцию через .as_view(). При использовании Router это делается автоматически.
Ошибка 3: перепутать аргументы router.register()
Симптом: URL не создаётся или создаётся с неожиданным именем.
# ОШИБКА: аргументы перепутаны
router.register(CategoryViewSet, r'categories') # ошибка!
# ПРАВИЛЬНО: сначала URL-префикс (строка), затем ViewSet (класс)
router.register(r'categories', CategoryViewSet)
Дополнительно: Третий опциональный аргумент basename используется для генерации имён URL. Если не указан, берётся из queryset.model._meta.object_name в нижнем регистре.
Ошибка 4: не указать queryset в ViewSet
Симптом: AssertionError: 'CategoryViewSet' should either include a 'queryset' attribute, or override the 'get_queryset()' method.
# ОШИБКА: нет queryset
class CategoryViewSet(viewsets.ModelViewSet):
serializer_class = CategorySerializer # нет queryset!
# ПРАВИЛЬНО:
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
Ошибка 5: использовать неверный Generic View для эндпоинта
Симптом: Запрос DELETE на /products/ (без pk) — код 405 Method Not Allowed.
# Проблема: ListCreateAPIView НЕ поддерживает DELETE
class ProductListCreateView(ListCreateAPIView):
...
# DELETE /products/ → 405 Method Not Allowed (ожидаемо!)
# Правильная структура:
# /products/ → ListCreateAPIView (GET список, POST создание)
# /products/{pk}/ → RetrieveUpdateDestroyAPIView (GET, PUT, PATCH, DELETE)
urlpatterns = [
path('products/', ProductListCreateView.as_view()), # GET, POST
path('products/<int:pk>/', ProductDetailView.as_view()), # GET, PUT, PATCH, DELETE
]
Правило: Всегда думай, какие HTTP-методы нужны для эндпоинта. Список-эндпоинт (без pk) — GET+POST, деталь-эндпоинт (с pk) — GET+PUT+PATCH+DELETE.
Ошибка 6: не установить django-filter перед использованием
Симптом: ModuleNotFoundError: No module named 'django_filters'
# Установка:
pip install django-filter
# Затем в settings.py:
INSTALLED_APPS = [
...
'django_filters',
]
# И в views.py:
from django_filters.rest_framework import DjangoFilterBackend
Обратите внимание: имя пакета при установке — django-filter (с дефисом), а при импорте и в INSTALLED_APPS — django_filters (с подчёркиванием).