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

Ошибки при работе с permissions, dumpdata и Swagger

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

  1. Забыть makemigrations после Meta.permissions — разрешение не появится в Admin
  2. has_permission вместо has_object_permission — object-level проверка не работает
  3. has_perm без app_labelhas_perm('can_view_statistics') всегда False
  4. loaddata без migrate — таблицы не существуют, ошибка IntegrityError
  5. drf_yasg не в INSTALLED_APPS — Swagger UI не загружает статику, пустая страница

Ошибка 1: Забыли makemigrations после Meta.permissions

Симптом

Разрешение can_view_statistics не появляется в Django Admin. has_perm() всегда возвращает False, даже для суперпользователя (в некоторых случаях).

Причина

Meta.permissions создаёт новую строку в таблице auth_permission, но только после применения миграций. Если не выполнить makemigrations + migrate — запись не создаётся.

Исправление

python manage.py makemigrations
python manage.py migrate

Ошибка 2: Только has_permission вместо has_object_permission

Симптом

Не-владелец может изменять чужой заказ. Разрешение не защищает конкретные объекты.

Причина

# Неправильно: только has_permission (view-level)
class IsCustomerOrReadOnly(BasePermission):
    def has_permission(self, request, view):
        return obj.customer == request.user  # NameError: obj не определён!

has_permission вызывается до обращения к объекту. Объект obj в этом методе недоступен. Object-level проверка — это has_object_permission.

Исправление

# Правильно: has_object_permission для object-level
class IsCustomerOrReadOnly(BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in ['GET', 'HEAD', 'OPTIONS']:
            return True
        return obj.customer == request.user

Ошибка 3: has_perm без app_label

Симптом

Эндпоинт статистики всегда возвращает 403, даже если пользователь состоит в группе "Statistic".

Причина

# Неправильно: без app_label
def has_permission(self, request, view):
    return request.user.has_perm('can_view_statistics')  # False всегда

Django требует полного имени разрешения в формате 'app_label.codename'.

Исправление

# Правильно: с app_label
def has_permission(self, request, view):
    return request.user.has_perm('store.can_view_statistics')

Ошибка 4: loaddata без предварительного migrate

Симптом

django.db.utils.OperationalError: no such table: store_order

Причина

После удаления БД (или создания новой) таблицы не существуют. loaddata пытается вставить данные в несуществующие таблицы.

Исправление

# Сначала создать структуру таблиц
python manage.py migrate

# Только потом загружать данные
python manage.py loaddata db_backup.json

Ошибка 5: drf_yasg не в INSTALLED_APPS

Симптом

Swagger UI открывается, но выглядит как пустая страница без стилей. В консоли браузера: 404 на статические файлы.

Причина

Статика (JS, CSS) Swagger UI берётся из пакета через Django staticfiles. Без добавления в INSTALLED_APPS Django не знает об этих файлах.

Исправление

# settings.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'drf_yasg',  # добавить!
]

Ошибка 6: perform_create не вызывает super()

Симптом

Объект не сохраняется. Нет ошибки, но данные не появляются в БД.

Причина

# Неправильно: вызывает super() вместо serializer.save()
def perform_create(self, serializer):
    super().perform_create(serializer)
    # customer не передан, значение берётся из запроса
    # (или вызывает ошибку если поле обязательное)

Исправление

# Правильно: serializer.save() с дополнительным полем
def perform_create(self, serializer):
    serializer.save(customer=self.request.user)

Ошибка 7: ContentType-конфликт при loaddata

Симптом

django.db.utils.IntegrityError: UNIQUE constraint failed: django_content_type.app_label, django_content_type.model

Причина

В дампе включены ContentType-записи. При migrate они уже созданы, и при loaddata возникает конфликт уникальности.

Исправление

# При создании дампа исключить проблемные таблицы:
python manage.py dumpdata \
  --exclude auth.permission \
  --exclude contenttypes \
  --indent=4 > db_backup.json
⚠️ Проверить по документации: поведение зависит от версии Django и структуры приложений. Флаги могут отличаться.
← К оглавлению урока    Ресурсы →