⚖️ Старый vs Новый API Django

Устаревшие паттерны из лекции и их современные аналоги

⚡ Что изменилось

  • choices: список кортежей → TextChoices (Django 3+)
  • Admin: admin.site.register(Model, AdminClass)@admin.register(Model)
  • Admin actions: for obj in queryset: obj.save()queryset.update(...)
  • unique_togetherUniqueConstraint (Django 4.x+)
  • ManyToManyField с null=True → только blank=True

1. Choices: список кортежей → TextChoices

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

STATUSES_CHOICES = [
    ('New', 'New'),
    ('In_progress', 'In_progress'),
    ('Completed', 'Completed'),
    ('Closed', 'Closed'),
]

class Task(models.Model):
    status = models.CharField(
        max_length=15,
        choices=STATUSES_CHOICES,
        default='New'
    )

Работает во всех версиях Django. Используется в практикуме.

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

class Task(models.Model):
    class Status(models.TextChoices):
        NEW = 'New', 'New'
        IN_PROGRESS = 'In_progress', 'In Progress'
        COMPLETED = 'Completed', 'Completed'
        CLOSED = 'Closed', 'Closed'

    status = models.CharField(
        max_length=15,
        choices=Status.choices,
        default=Status.NEW
    )

Поддержка автодополнения, строгая типизация.

2. Регистрация в Admin

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

class ProjectAdmin(admin.ModelAdmin):
    list_display = ['name']

admin.site.register(Project, ProjectAdmin)

Работает, но устарело.

Современное (рекомендуется)

@admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
    list_display = ['name']

Декоратор — стандарт с Django 1.7.

3. Admin-действия: for obj + save() → queryset.update()

Из лекции (из практикума)

def change_status(self, request, objects):
    for obj in objects:
        obj.status = 'Closed'
        obj.save()
    return objects

N запросов к БД (по одному на объект). Параметр называется queryset по конвенции.

Современное (эффективно)

def change_status(self, request, queryset):
    queryset.update(status='Closed')
    # Один SQL UPDATE запрос

Один запрос к БД. Рекомендуется для массовых операций.

⚠️ Важно: при queryset.update() не вызываются save() и сигналы post_save. Если у модели есть логика в save() — используйте цикл с obj.save().

4. unique_together → UniqueConstraint

Из лекции (устаревшее)

class Meta:
    unique_together = (('title', 'project'),)

Работает, но помечено deprecated в Django 4.2.

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

from django.db.models import UniqueConstraint

class Meta:
    constraints = [
        UniqueConstraint(
            fields=['title', 'project'],
            name='unique_task_in_project'
        )
    ]

Более гибко, поддерживает условные ограничения.

5. ManyToManyField: null=True → только blank=True

Из лекции (неверно)

tags = models.ManyToManyField(
    'Tag',
    null=True,    # ← Django игнорирует это!
    blank=True,
    related_name='tasks'
)

Django выдаёт SystemCheck warning: null=True не имеет смысла для M2M.

Современное (правильно)

tags = models.ManyToManyField(
    'Tag',
    blank=True,   # ← только blank=True
    related_name='tasks'
)

Для M2M "пустое" означает отсутствие записей в промежуточной таблице. null=True не нужен.