🐛 Типичные ошибки при работе с Django-моделями

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

  1. Забыть добавить приложение в INSTALLED_APPSmakemigrations не видит модели
  2. ForeignKey без on_deleteTypeError в Django 2.0+
  3. Не добавить null=True при on_delete=models.SET_NULL
  4. Применить изменения без makemigrations + migrate
  5. Использовать timezone.now() (с вызовом) вместо timezone.now (без) в default=

Ошибка 1: Приложение не в INSTALLED_APPS

Ошибка: python manage.py makemigrations завершается с «No changes detected» даже после изменений в models.py.

Причина: Приложение library не зарегистрировано в settings.py.

Неправильно:

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    # library отсутствует!
]

Правильно:

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'library',  # добавить!
]

Ошибка 2: ForeignKey без on_delete

Ошибка: TypeError: __init__() missing 1 required positional argument: 'on_delete'

Неправильно:

author = models.ForeignKey(Author)
# Django 2.0+ требует on_delete

Правильно:

author = models.ForeignKey(
    Author,
    on_delete=models.SET_NULL,
    null=True
)

Ошибка 3: SET_NULL без null=True

Ошибка: django.db.utils.IntegrityError: NOT NULL constraint failed

Если используется on_delete=models.SET_NULL, поле в БД должно допускать NULL.

Неправильно:

author = models.ForeignKey(
    Author,
    on_delete=models.SET_NULL
    # null=True отсутствует!
)

Правильно:

author = models.ForeignKey(
    Author,
    on_delete=models.SET_NULL,
    null=True  # обязательно!
)

Ошибка 4: Забыть применить миграции

Ошибка: django.db.utils.OperationalError: no such column: library_author.profile

Причина: Поле добавлено в модель, но миграция не создана или не применена.

# Правильный порядок после изменения models.py:
python manage.py makemigrations  # создать файл миграции
python manage.py migrate         # применить к БД

Ошибка 5: default=timezone.now() с вызовом

Ошибка: Все записи получают одно и то же значение даты — дату запуска сервера.

Неправильно:

registration_date = models.DateField(
    default=timezone.now()  # вызов ()!
    # Дата вычисляется один раз при старте
)

Правильно:

registration_date = models.DateField(
    default=timezone.now  # без ()
    # Функция вызывается при создании объекта
)

Ошибка 6: null и blank — путаница

Это часто путают:

  • null=True — разрешает NULL в базе данных (SQL)
  • blank=True — разрешает пустое значение в Django-формах и Admin

Только null=True:

profile = models.URLField(null=True)
# В БД: NULL разрешён
# В Admin: поле ОБЯЗАТЕЛЬНО к заполнению
# → форма не примет пустое значение!

null=True + blank=True:

profile = models.URLField(null=True, blank=True)
# В БД: NULL разрешён
# В Admin: поле можно оставить пустым
# → правильно для необязательных полей

Ошибка 7: Циклические зависимости в ForeignKey

Ошибка: NameError: name 'Library' is not defined

Причина: Модель использует другую модель, которая определена ниже в файле.

Неправильно (Library не определена ещё):

class Member(models.Model):
    libraries = models.ManyToManyField(
        Library,  # NameError!
        related_name='members'
    )

class Library(models.Model):
    ...

Правильно (строка с именем):

class Member(models.Model):
    libraries = models.ManyToManyField(
        'Library',  # строка — ОК
        related_name='members'
    )

class Library(models.Model):
    ...

Ошибка 8: Validators не выполняются в shell

Важно: MinValueValidator и MaxValueValidator срабатывают только при валидации форм или ручном вызове model.full_clean(). Прямое создание объекта в shell обходит валидаторы.
# Это НЕ вызовет ошибку (валидатор пропущен):
author = Author.objects.create(rating=999)

# Это вызовет ValidationError:
author = Author(rating=999)
author.full_clean()  # явная проверка
author.save()

Ошибка 9: Удаление модели без миграции

Задача 9 предполагает удаление Publisher. Нельзя просто удалить класс из models.py — нужно создать миграцию.

# 1. Удалить класс Publisher из models.py
# 2. Изменить Book.publisher_id на ForeignKey(Member, ...)
# 3. Создать и применить миграцию:
python manage.py makemigrations
python manage.py migrate
Если в БД уже есть данные в таблице Publisher, Django предупредит о каскадном удалении данных. В разработке это нормально, в продакшн — нужно мигрировать данные вручную.