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

🎯 Из лекции (старое) → Django 5.x (новое) К оглавлению урока

⚡ Ключевые изменения

  • index_together → indexes — index_together считается устаревшим; используй models.Index в indexes.
  • unique_together → UniqueConstraint — предпочтительный современный способ.
  • admin.site.register → @admin.register — декоратор удобнее и более Pythonic.
  • actions как функции → methods — в Django 5.x действия оформляются как методы ModelAdmin.
  • get_or_create / update_or_create — используй вместо ручных try/except при частом паттерне.

1. index_together → indexes (устарело в Django 4.2)

Из лекции (старое): использовался index_together.
# СТАРЫЙ СПОСОБ (из лекции) — устарело
class Meta:
    index_together = ('title', 'author')
# СОВРЕМЕННЫЙ СПОСОБ — Django 5.x
class Meta:
    indexes = [
        models.Index(fields=['title', 'author']),
        models.Index(fields=['published_date'], name='published_idx'),
    ]

Почему: indexes гибче — поддерживает именованные индексы, частичные индексы, тип индекса и другие параметры. index_together объявлен устаревшим и будет удалён в будущем.

2. unique_together → UniqueConstraint (рекомендовано с Django 2.2)

Из лекции (старое): unique_together в классе Meta.
# СТАРЫЙ СПОСОБ (из лекции) — ещё работает, но устарело
class Meta:
    unique_together = ('title', 'author')
# СОВРЕМЕННЫЙ СПОСОБ — Django 5.x
from django.db.models import UniqueConstraint

class Meta:
    constraints = [
        UniqueConstraint(fields=['title', 'author'], name='unique_title_author'),
    ]

Почему: UniqueConstraint поддерживает условные (partial) ограничения и именование, что важно для миграций и консистентности на уровне БД.

3. admin.site.register → @admin.register

Из лекции: оба способа показаны. Декоратор предпочтителен.
# СТАРЫЙ СПОСОБ (из лекции — способ 1)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author')

admin.site.register(Book, BookAdmin)
# СОВРЕМЕННЫЙ СПОСОБ (из лекции — способ 2, рекомендуется)
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author')

Почему: декоратор связывает класс и модель в одном месте, исключает возможность забыть вызов register.

4. Action как глобальная функция → метод ModelAdmin

Из лекции (старое): action определялся как отдельная функция вне класса.
# СТАРЫЙ СПОСОБ (из лекции)
def update_created_at(modeladmin, request, queryset):
    queryset.update(created_at=timezone.now())

update_created_at.short_description = "Update created_at to current time"

class BookAdmin(admin.ModelAdmin):
    actions = [update_created_at]
# СОВРЕМЕННЫЙ СПОСОБ — Django 5.x (метод класса)
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    actions = ['update_created_at']

    @admin.action(description="Update created_at to current time")
    def update_created_at(self, request, queryset):
        queryset.update(created_at=timezone.now())

Почему: декоратор @admin.action появился в Django 3.2. Метод класса лучше инкапсулирует логику, а @admin.action(description=...) заменяет присвоение short_description.

5. Ручная обработка get() → get_or_create / update_or_create

# СТАРЫЙ СПОСОБ — много кода
try:
    obj = Book.objects.get(title="The Great Gatsby")
except Book.DoesNotExist:
    obj = Book.objects.create(title="The Great Gatsby", author="Fitzgerald", published_date="1925-04-10")
# СОВРЕМЕННЫЙ СПОСОБ
obj, created = Book.objects.get_or_create(
    title="The Great Gatsby",
    defaults={"author": "Fitzgerald", "published_date": "1925-04-10"}
)

Почему: get_or_create атомарен (использует SELECT + INSERT в транзакции) и исключает дублирование кода.