🐛 Типичные ошибки — Урок 33
⚡ Топ-5 ошибок
- Забыть добавить
'django_filters'в INSTALLED_APPS послеpip install django-filter - Не вызвать
super().get_serializer_context()— теряютсяrequest,format,view - Параметр URL в
<str:param>не совпадает сlookup_url_kwarg - Не вызвать
self.check_object_permissions()в переопределённомget_object() - Использовать
filter()вместоget()вget_object()— возвращает QuerySet, а не объект
Ошибки с lookup_field и lookup_url_kwarg
Ошибка 1: параметр URL не совпадает с lookup_url_kwarg
Симптом: AssertionError: Expected view ... to be called with a URL keyword argument named "genre_name". Fix your URL conf...
# НЕПРАВИЛЬНО — параметр URL 'name' не совпадает с lookup_url_kwarg 'genre_name'
# views.py
class GenreDetailView(RetrieveUpdateDestroyAPIView):
lookup_url_kwarg = 'genre_name'
# urls.py
path('genres/<str:name>/', GenreDetailView.as_view()) # ← name ≠ genre_name
# ПРАВИЛЬНО — параметры совпадают
# urls.py
path('genres/<str:genre_name>/', GenreDetailView.as_view())
Ошибка 2: lookup_field указывает на неуникальное поле
Симптом: MultipleObjectsReturned при запросе.
# НЕПРАВИЛЬНО — поле author не уникально, по нему несколько книг
class BookDetailView(RetrieveAPIView):
lookup_field = 'author' # не уникальное поле!
# ПРАВИЛЬНО — использовать только уникальное поле
class BookDetailView(RetrieveAPIView):
lookup_field = 'isbn' # уникальное поле
# Или оставить pk (значение по умолчанию)
Ошибки с get_object()
Ошибка 3: использование filter() вместо get()
Симптом: представление возвращает объект QuerySet, а не модель. Сериализатор падает с ошибкой или возвращает неверные данные.
# НЕПРАВИЛЬНО — filter() возвращает QuerySet, не объект
def get_object(self):
pk = self.kwargs.get('pk')
book = self.queryset.filter(pk=pk, is_banned=False) # QuerySet!
return book
# ПРАВИЛЬНО — get() возвращает единственный объект
def get_object(self):
pk = self.kwargs.get('pk')
try:
book = self.queryset.get(pk=pk, is_banned=False)
except Book.DoesNotExist:
raise NotFound(f"Book with id '{pk}' not found or is banned.")
return book
Ошибка 4: забыть check_object_permissions()
Симптом: object-level permissions не работают — любой пользователь получает доступ к любому объекту.
# НЕПРАВИЛЬНО — object-level permissions игнорируются
def get_object(self):
pk = self.kwargs.get('pk')
obj = get_object_or_404(Book, pk=pk)
return obj # ← без проверки прав!
# ПРАВИЛЬНО
def get_object(self):
pk = self.kwargs.get('pk')
obj = get_object_or_404(Book, pk=pk)
self.check_object_permissions(self.request, obj) # явный вызов
return obj
Ошибки с get_serializer_context()
Ошибка 5: не вызывать super()
Симптом: HyperlinkedRelatedField или HyperlinkedModelSerializer падает с AssertionError: `HyperlinkedRelatedField` requires the request in the serializer context.
# НЕПРАВИЛЬНО — request/format/view потеряны
def get_serializer_context(self):
return {'include_related': True} # только наш ключ!
# ПРАВИЛЬНО
def get_serializer_context(self):
context = super().get_serializer_context() # {'request', 'format', 'view'}
context['include_related'] = True
return context
Ошибка 6: обращение к контексту без проверки наличия ключа
Симптом: KeyError в сериализаторе при прямом вызове (unit-тесты, вложенные сериализаторы).
# НЕБЕЗОПАСНО — ключ может отсутствовать
if self.context['include_related']: # KeyError если ключа нет
# БЕЗОПАСНО — использовать .get() с дефолтным значением
if self.context.get('include_related', False):
Ошибки с filter_backends
Ошибка 7: не добавить django_filters в INSTALLED_APPS
Симптом: ImproperlyConfigured: 'django_filters' must be in INSTALLED_APPS to use DjangoFilterBackend
# НЕПРАВИЛЬНО
pip install django-filter
# settings.py — забыли добавить!
INSTALLED_APPS = ['django.contrib.admin', ...] # django_filters отсутствует
# ПРАВИЛЬНО
INSTALLED_APPS = [
...
'django_filters', # обязательно добавить
]
Ошибка 8: неверное имя параметра в запросе
Симптом: фильтрация не работает, запрос возвращает все данные без фильтрации.
# НЕПРАВИЛЬНО — SearchFilter использует ?search=, не ?q=
GET /books/?q=Gatsby # ← игнорируется!
GET /books/?filter=Tolstoy # ← тоже игнорируется
# ПРАВИЛЬНО — стандартные имена параметров
GET /books/?search=Gatsby # SearchFilter
GET /books/?author=Tolstoy # DjangoFilterBackend (filterset_fields)
GET /books/?ordering=price # OrderingFilter
Ошибка 9: забыть минус для сортировки по убыванию
Симптом: данные всегда сортируются по возрастанию.
# Сортировка по возрастанию (по умолчанию)
GET /books/?ordering=price
# Сортировка по убыванию (нужен минус перед именем поля)
GET /books/?ordering=-price # ← минус важен!