// 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
11. Swagger UI не показывает JWT-защищённые эндпоинты корректно
Проблема
# В Swagger UI кнопка Authorize не работает с JWT
# — DEFAULT_AUTHENTICATION_CLASSES не содержит JWTAuthentication
# — DEFAULT_SCHEMA_CLASS не переключён на drf-spectacular