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

К оглавлению урока

⚡ Главное изменение

QuerySet API Django стабилен с версии 1.x — базовые методы (filter, get, Q) не изменились. Эволюция затронула расширенные возможности: select_related, annotate, F-объекты, async QuerySet.

Контекст
Лекция (Django 3.x–4.x) и Django 5.x используют идентичный QuerySet API для базовых операций. Все примеры из лекции (filter, get, Q, lookups) работают в Django 5.x без изменений. На этой странице показаны области, где поведение или рекомендации эволюционировали.

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

Из лекции (Django 3.x–4.x)

# Используется ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist

try:
    book = Book.objects.get(title='Book')
    print(f"Найдена: {book.title}")
except ObjectDoesNotExist:
    print("Книга не найдена.")

Оба подхода работают в любой версии Django.

Современная практика (Django 5.x)

# Предпочтительно — исключение конкретной модели
try:
    book = Book.objects.get(title='Book')
    print(f"Найдена: {book.title}")
except Book.DoesNotExist:
    print("Книга не найдена.")
except Book.MultipleObjectsReturned:
    print("Несколько записей.")

# Или — get_or_create() чтобы избежать исключения
book, created = Book.objects.get_or_create(
    title='Book',
    defaults={'author': 'Unknown', 'published_date': '2024-01-01'}
)

2. Булевы условия в filter() — устаревший стиль

Из лекции

# NOT через exclude()
# (лекция использует ~Q для NOT)
books = Book.objects.filter(~Q(is_bestseller=True))

Современный эквивалент

# exclude() — читаемее для простого NOT
books = Book.objects.exclude(is_bestseller=True)

# ~Q() — лучше для сложных вложенных условий
books = Book.objects.filter(
    ~Q(is_bestseller=True) & Q(price__lt=50)
)

3. Методы, отсутствующие в лекции (Django 4.x+)

Метод / функцияВерсия DjangoОписание
aget(), afilter(), aall() 4.1+ Async-версии QuerySet методов для async views
get_or_create() Давно Найти или создать запись — атомарно
update_or_create() Давно Обновить или создать — атомарно
select_related() Давно JOIN для ForeignKey/OneToOne — избегает N+1
prefetch_related() Давно Предзагрузка ManyToMany / обратные FK
annotate() Давно Добавить вычисляемые поля к каждой записи
aggregate() Давно Агрегация по всему QuerySet (COUNT, SUM, AVG...)
⚠️ Проверить по документации: async QuerySet API (aget(), afilter() и др.) появился в Django 4.1 и развивается в 5.x. Для синхронных проектов изменений нет. Django 5.x QuerySet docs

4. Современные дополнения к Q-объектам

# Django 4.0+ — Q-объекты теперь можно комбинировать через XOR (^)
# (в лекции XOR не упоминается)
from django.db.models import Q

# XOR — ровно одно из условий истинно
books = Book.objects.filter(
    Q(is_bestseller=True) ^ Q(price__lt=10)
)
⚠️ Проверить по документации: XOR-оператор (^) для Q-объектов добавлен в Django 4.0. На базах без поддержки XOR Django эмулирует его через SQL.