⚖️ Старый vs Новый: устаревшие паттерны Django

⚡ Кратко: что изменилось

  • NullBooleanField устарел → используйте BooleanField(null=True)
  • ForeignKey без on_delete → теперь on_delete обязателен
  • choices как список кортежей → лучше использовать TextChoices / IntegerChoices
  • AutoField как pk → заменён на BigAutoField по умолчанию
Контекст: лекция написана на Django 3.x / 4.x. На Django 5.x ряд паттернов считается устаревшим или изменился. Этот раздел показывает, что нужно изменить при работе с актуальной версией.

1. NullBooleanField → BooleanField(null=True)

Из лекции (старое — Django 2.x/3.x)

# Поле для логического значения с возможностью NULL
# NullBooleanField — УСТАРЕЛО с Django 4.0, удалено в Django 5.x
is_active = models.NullBooleanField()

Современное (Django 5.x)

# Правильный способ хранить True/False/NULL
is_active = models.BooleanField(null=True, blank=True)

Почему изменили: NullBooleanField дублировал функцию обычного BooleanField(null=True). В Django 4.0 он объявлен устаревшим, в Django 5.x — удалён. Старый код вызовет ImproperlyConfigured при запуске.

2. ForeignKey без on_delete → on_delete обязателен

Из лекции (старое — до Django 2.0)

# В Django 1.x on_delete было необязательным (DEFAULT: CASCADE)
author = models.ForeignKey(Author)

Современное (Django 5.x)

# on_delete ОБЯЗАТЕЛЕН — нужно явно указать поведение
author = models.ForeignKey(Author, on_delete=models.CASCADE)

# Или другие варианты:
author = models.ForeignKey(Author, on_delete=models.PROTECT)
author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True)

Почему изменили: неявное поведение CASCADE приводило к случайному массовому удалению данных. Начиная с Django 2.0, параметр on_delete обязателен — ошибка TypeError возникает при запуске, если его не указать.

3. choices как список кортежей → TextChoices / IntegerChoices

Из лекции (старое, но работает)

# Список кортежей — работает и сейчас, но менее удобен
STATUS_CHOICES = [
    ('draft', 'Draft'),
    ('published', 'Published'),
]
status = models.CharField(max_length=10, choices=STATUS_CHOICES)

Современное (Django 3.0+)

# TextChoices — перечисление с автодополнением, защита от опечаток
class Status(models.TextChoices):
    DRAFT = 'draft', 'Черновик'
    PUBLISHED = 'published', 'Опубликовано'

status = models.CharField(
    max_length=10,
    choices=Status.choices,
    default=Status.DRAFT
)

# Преимущество: использование констант вместо строк
if article.status == Status.PUBLISHED:
    ...
# вместо:
if article.status == 'published':    # можно опечататься
    ...

Почему лучше: IDE даёт автодополнение, статический анализ ловит опечатки, код читается чище. Старый формат кортежей продолжает работать — это не ошибка, но TextChoices — best practice.

4. AutoField → BigAutoField (первичный ключ)

Из лекции (старое)

# В старых проектах и в лекции — AutoField (32-битный int)
# В settings.py явно не задавалось или:
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

Современное (Django 3.2+ по умолчанию)

# Django 3.2+ использует BigAutoField по умолчанию
# В settings.py (уже стоит в новых проектах):
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# BigAutoField — 64-битный, диапазон: 1 до 9,223,372,036,854,775,807
# Практически неограниченный счётчик записей

Почему изменили: 32-битный AutoField вмещает до ~2,1 млрд записей. Для высоконагруженных систем этого недостаточно. BigAutoField снимает это ограничение.

5. db_index на поле → Meta.indexes

Старый подход (лекция)

# db_index прямо на поле — работает
email = models.CharField(max_length=200, db_index=True)

Современный подход (составные индексы, именованные)

class Article(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

    class Meta:
        # Простой индекс через Meta — более гибко
        indexes = [
            models.Index(fields=['author']),
            # Составной индекс по нескольким полям
            models.Index(fields=['author', 'published_date'], name='author_date_idx'),
        ]

Когда какой подход: db_index=True на поле — быстро и просто для одного поля. Meta.indexes — для составных индексов, именованных индексов и более тонкой настройки.

Итоговая таблица сравнений

Из лекции (старое) Django 5.x (современное) Статус
NullBooleanField() BooleanField(null=True) Удалено в 5.x
ForeignKey(Model) без on_delete ForeignKey(Model, on_delete=CASCADE) Ошибка с 2.0
choices=[('a','A'),...] class Status(TextChoices) Работает, но устаревший стиль
AutoField как pk BigAutoField (по умолчанию с 3.2) AutoField работает, но BigAutoField лучше
db_index=True Meta.indexes для составных Оба работают, Meta гибче