🐛 Типичные ошибки практикума 8

⚡ Топ-5 ошибок

  1. Забыть 'django_filters' в INSTALLED_APPSDjangoFilterBackend не работает
  2. Не вызвать .as_view() при регистрации Generic View в urlpatterns
  3. Спутать порядок аргументов router.register(r'url-prefix', ViewSetClass)
  4. Использовать Generic View вместо ViewSet для простых моделей (лишний код)
  5. Не установить пакет 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_APPSdjango_filters (с подчёркиванием).

← К оглавлению урока    ← Решения    Ресурсы →