🐛 Частые ошибки Django-блока
⚡ Топ-3 ошибки
- Приложение не в INSTALLED_APPS — миграции не создаются, модели не видны.
- Новое поле без null/default — Django не может применить миграцию к существующим записям.
- makemigrations без migrate — файл миграции создан, но изменения не применены к БД.
Ошибки при создании проекта и приложений
Ошибка 1: Приложение не зарегистрировано в INSTALLED_APPS
Симптом: python manage.py makemigrations пишет «No changes detected», хотя модели были изменены. Admin не показывает модели.
Причина: Приложение создано командой startapp, но не добавлено в INSTALLED_APPS.
# Неправильно: приложение есть, но Django о нём не знает
INSTALLED_APPS = [
'django.contrib.admin',
...
] # myapp отсутствует
# Правильно:
INSTALLED_APPS = [
'django.contrib.admin',
...
'myapp.apps.MyappConfig', # Добавлено
]
Ошибка 2: SECRET_KEY в коде репозитория
Симптом: Реальный SECRET_KEY виден в git-истории. При компрометации злоумышленник может подделать сессии и CSRF-токены.
Правило: Никогда не коммитить настоящий SECRET_KEY. Использовать .env + .gitignore.
# .gitignore — добавить обязательно
.env
*.pyc
__pycache__/
db.sqlite3
Ошибки в моделях
Ошибка 3: Новое поле без null=True или default
Симптом: При makemigrations Django спрашивает «Provide a one-off default». Если принудительно применить — IntegrityError в БД.
# Неправильно — существующие записи получат NULL (но поле NOT NULL)
class Book(models.Model):
title = models.CharField(max_length=200)
rating = models.IntegerField() # Добавлено без default
# Правильно — указать значение по умолчанию
class Book(models.Model):
title = models.CharField(max_length=200)
rating = models.IntegerField(default=0) # OK
# или: null=True для необязательных числовых полей
Ошибка 4: Путаница null и blank для строковых полей
Симптом: Форма принимает пустую строку, но в БД попадает пустая строка (""), а не NULL. Или наоборот.
# Для строковых полей — обычно оба
optional_name = models.CharField(max_length=100, blank=True, null=True)
# Для числовых и дат — только null
optional_age = models.IntegerField(null=True)
# Плохо: только blank без null для числового поля
age = models.IntegerField(blank=True) # blank=True на числовых — почти не используется
Ошибка 5: CharField без max_length
Симптом: SystemCheckError: ERRORS: myapp.Book.title: (fields.E120) CharField does not define a 'max_length' attribute.
# Неправильно
title = models.CharField() # max_length обязателен!
# Правильно
title = models.CharField(max_length=200)
Ошибки с миграциями
Ошибка 6: makemigrations без migrate
Симптом: Файл миграции создан в папке migrations/, но в БД изменений нет. Сервер выдаёт предупреждение «You have N unapplied migration(s)».
Правило: После makemigrations всегда выполнять migrate.
python manage.py makemigrations # 1. Создать
python manage.py migrate # 2. Применить — обязательно!
Ошибка 7: Редактирование файлов миграций вручную
Симптом: После ручного редактирования migrations/*.py при следующем migrate возникают конфликты или InconsistentMigrationHistory.
Правило: Не редактировать файлы миграций вручную без понимания последствий. Для исправления — создать новую миграцию.
Ошибки в Admin
Ошибка 8: Модель не зарегистрирована в admin.py
Симптом: Модель создана и применена через миграцию, но в /admin/ не отображается.
# admin.py — не забыть добавить!
from django.contrib import admin
from .models import MyModel
admin.site.register(MyModel) # Без этой строки — модель не видна в admin
Ошибка 9: Попытка войти в /admin/ без createsuperuser
Симптом: Форма входа в /admin/ выдаёт «Please enter the correct username and password».
Решение: Создать суперпользователя командой python manage.py createsuperuser. Обычные пользователи не имеют доступа к admin.
Ошибки со связями
Ошибка 10: ForeignKey без on_delete
Симптом: TypeError: __init__() missing 1 required positional argument: 'on_delete'
# Неправильно — on_delete обязателен с Django 2.0
author = models.ForeignKey(Author) # Ошибка!
# Правильно
author = models.ForeignKey(Author, on_delete=models.CASCADE)
Ошибка 11: Циклический импорт при связях
Симптом: ImportError или AppRegistryNotReady при импорте моделей из разных приложений.
Решение: Использовать строку вместо класса в ForeignKey:
# Если Book в другом приложении 'library'
author = models.ForeignKey('library.Book', on_delete=models.CASCADE)
# Строка 'app.ModelName' — Django сам разрешит зависимость