🐛 Частые ошибки Django-блока

🎯 Разбор типичных проблем К оглавлению урока

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

  1. get() без try/except — всегда оборачивай в try/except DoesNotExist.
  2. AUTH_USER_MODEL после миграции — кастомный User нужно прописать ДО первой миграции.
  3. Нет makemigrations после изменения модели — изменения в models.py не применяются без миграций.

1. get() без обработки исключений

Проблема

# Опасно — упадёт при отсутствии записи
book = Book.objects.get(title="The Great Gatsby")

Решение

from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned

try:
    book = Book.objects.get(title="The Great Gatsby")
except ObjectDoesNotExist:
    book = None
    print("Книга не найдена")
except MultipleObjectsReturned:
    book = Book.objects.filter(title="The Great Gatsby").first()
    print("Несколько книг, берём первую")

2. AUTH_USER_MODEL прописан после первой миграции

Проблема

Разработчик создаёт кастомный User и прописывает AUTH_USER_MODEL после того, как уже выполнил migrate. Результат — конфликты между auth-таблицами, невозможность применить миграции.

Решение

Всегда создавай CustomUser и прописывай AUTH_USER_MODEL до первой миграции. Если уже есть данные — нужно пересоздать БД или использовать сложные миграции.

# settings.py — до первой миграции
AUTH_USER_MODEL = 'myapp.CustomUser'

# После этого:
python manage.py makemigrations
python manage.py migrate

3. Забыли выполнить makemigrations после изменения модели

Проблема

Добавили поле в модель, но не запустили makemigrations. Django продолжает работать со старой схемой БД. Ошибка появляется в рантайме при попытке обращения к новому полю.

Решение

# После каждого изменения модели
python manage.py makemigrations
python manage.py migrate

# Проверка состояния
python manage.py showmigrations

4. Добавление поля без null=True или default

Проблема

При добавлении нового поля к модели с существующими данными Django не знает, какое значение записать в уже существующие строки. makemigrations зависнет в интерактивном режиме или упадёт.

# Проблема — нет default и null=True
class Book(models.Model):
    rating = models.FloatField()  # существующие записи?

Решение

# Указать default или null=True
class Book(models.Model):
    rating = models.FloatField(null=True, blank=True)
    # или
    rating = models.FloatField(default=0.0)

5. index_together вместо indexes (устарело)

Проблема

class Meta:
    index_together = ('title', 'author')  # deprecated в Django 4.2

Решение

class Meta:
    indexes = [
        models.Index(fields=['title', 'author']),
    ]

6. Зарегистрировать модель, не добавленную в INSTALLED_APPS

Проблема

Создаётся приложение, в admin.py регистрируется модель, но приложение не добавлено в INSTALLED_APPS. Django его игнорирует — модели не видны в admin.

Решение

# settings.py
INSTALLED_APPS = [
    ...
    'myapp.apps.MyappConfig',  # обязательно!
]

7. bulk_create не вызывает сигналы save

Проблема

Используется bulk_create, но в проекте есть логика в pre_save / post_save сигналах. Bulk-операции обходят сигналы Django.

Решение

Если нужны сигналы — используй обычный цикл с save(). Если сигналы не нужны (массовый импорт данных) — bulk_create правильный выбор.

8. N+1 проблема при обходе связанных объектов

Проблема

# Для каждой книги выполняется отдельный SQL-запрос к Publisher
books = Book.objects.all()
for book in books:
    print(book.publisher.name)  # N+1 запросов!

Решение

# select_related — JOIN для ForeignKey / OneToOneField
books = Book.objects.select_related('publisher').all()
for book in books:
    print(book.publisher.name)  # один запрос с JOIN
⚠️ Проверить по документации: для ManyToManyField используй prefetch_related вместо select_related.