🐛 Частые ошибки: блок Auth
⚡ Топ-3 ошибки
- Забыть 'rest_framework.authtoken' в INSTALLED_APPS → Token таблица не создана.
- Не зарегистрировать сигналы в AppConfig.ready() → обработчики не вызываются.
- Хранить JWT в localStorage → уязвимость XSS. Используй httpOnly-куки.
Аутентификация и токены
1. rest_framework.authtoken не добавлен в INSTALLED_APPS
Проблема
# Забыли добавить authtoken
INSTALLED_APPS = ['django.contrib.auth', 'rest_framework']
# Ошибка: django.db.utils.OperationalError: no such table: authtoken_token
Исправление
INSTALLED_APPS = [
'django.contrib.auth',
'rest_framework',
'rest_framework.authtoken', # добавить!
]
# + python manage.py migrate
2. Неверный формат заголовка Authorization
Проблема
# TokenAuthentication — неверно:
Authorization: Bearer abc123 # DRF ожидает "Token", не "Bearer"
# JWTAuthentication — неверно:
Authorization: Token eyJhbGci... # SimpleJWT ожидает "Bearer"
Исправление
# TokenAuthentication:
Authorization: Token abc123...
# JWTAuthentication (SimpleJWT):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
3. JWT в localStorage вместо httpOnly-куки
Проблема (небезопасно)
// XSS может украсть токен!
localStorage.setItem('access_token', data.access);
Исправление
# Сервер: httpOnly-куки недоступны JavaScript
response.set_cookie(
'access_token',
value=str(access_token),
httponly=True, # JS не может прочитать
secure=True, # только HTTPS
samesite='Lax', # защита от CSRF
)
Разрешения
4. has_object_permission() не вызывается автоматически
Проблема
# Разработчик думает, что has_object_permission() проверяется всегда
# Но при ListAPIView get_queryset() не вызывает get_object()
# → has_object_permission() НЕ вызывается для списка
Исправление
# has_object_permission() вызывается ТОЛЬКО при get_object()
# (RetrieveAPIView, UpdateAPIView, DestroyAPIView)
# Для ListAPIView фильтруй queryset в get_queryset():
def get_queryset(self):
return Book.objects.filter(owner=self.request.user)
5. read_only_fields не установлено для owner
Проблема
# Пользователь может подменить owner в теле запроса!
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__' # owner включён и изменяем
Исправление
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
read_only_fields = ['owner'] # нельзя изменить через API
6. Забыть выполнить migrate после добавления Meta.permissions
Проблема
# Добавили permissions в Meta, но не сделали migrate
class Genre(models.Model):
class Meta:
permissions = [('can_get_statistic', 'Can get genres statistic')]
# request.user.has_perm('first_app.can_get_statistic') → всегда False!
Исправление
python manage.py makemigrations
python manage.py migrate
# Теперь разрешение появится в Django Admin → Permissions
Сигналы
7. Сигналы не регистрируются — не импортированы в ready()
Проблема
# apps.py — забыли импортировать сигналы
class FirstAppConfig(AppConfig):
name = 'first_app'
# ready() не переопределён → сигналы не подключены → обработчики не вызываются
Исправление
class FirstAppConfig(AppConfig):
name = 'first_app'
def ready(self):
import first_app.signals # обязательно!
8. Бесконечный цикл в post_save сигнале
Проблема
@receiver(post_save, sender=Book)
def update_book(sender, instance, **kwargs):
instance.title = instance.title.strip()
instance.save() # снова вызывает post_save → бесконечный цикл!
Исправление
# Вариант 1: update без сохранения через ORM
@receiver(post_save, sender=Book)
def update_book(sender, instance, **kwargs):
Book.objects.filter(pk=instance.pk).update(title=instance.title.strip())
# Вариант 2: использовать pre_save (до сохранения)
@receiver(pre_save, sender=Book)
def clean_title(sender, instance, **kwargs):
instance.title = instance.title.strip()
# save() не нужен — это pre_save, изменения применятся автоматически
9. EMAIL_BACKEND не настроен — send_mail падает с ошибкой
Проблема
# В settings.py нет настройки EMAIL_BACKEND
# При вызове send_mail() — ConnectionRefusedError или SMTPAuthenticationError
Исправление
# Для разработки (письма выводятся в консоль):
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
# Для продакшн (реальный Gmail SMTP):
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your@gmail.com'
EMAIL_HOST_PASSWORD = 'app_password' # не обычный пароль — App Password Google
SimpleJWT
10. rest_framework_simplejwt.token_blacklist не добавлен для BLACKLIST_AFTER_ROTATION
Проблема
# В settings.py включили blacklist, но не добавили приложение
SIMPLE_JWT = {'BLACKLIST_AFTER_ROTATION': True}
# Ошибка: ImproperlyConfigured — rest_framework_simplejwt.token_blacklist not in INSTALLED_APPS
Исправление
INSTALLED_APPS = [
...
'rest_framework_simplejwt',
'rest_framework_simplejwt.token_blacklist', # добавить!
]
# + python manage.py migrate
11. Swagger не видит JWT-защищённые эндпоинты корректно
Проблема
# В Swagger UI кнопка Authorize не работает с JWT
# — get_schema_view не сконфигурирован с security definitions
Исправление
schema_view = get_schema_view(
openapi.Info(title="API", default_version='v1'),
public=True,
permission_classes=[permissions.AllowAny],
)
# В Swagger UI: кнопка "Authorize" → Bearer <access_token>
⚠️ Проверить по документации: конфигурация security schemes в drf-yasg может отличаться в разных версиях. Проверьте актуальную документацию drf-yasg.