Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как строится запрос в Django ORM
Джанго ORM построен на основе Query Builder паттерна и использует ленивое вычисление (lazy evaluation). Запрос не выполняется, пока вы явно не материализуете результат.
Основные компоненты запроса
QuerySet — основной объект для построения запросов. Это не список данных, а описание запроса к БД, которое может быть изменено и распространено.
from django.contrib.auth.models import User
# QuerySet создан, но SQL не выполнен
users = User.objects.filter(is_active=True)
# SQL запрос выполнится только здесь при итерации
for user in users:
print(user.username)
Цепочка методов (Method Chaining)
Запросы в Django строятся через цепочку методов, каждый из которых возвращает новый QuerySet:
users = (
User.objects
.filter(is_active=True) # WHERE is_active = 1
.filter(date_joined__year=2024) # WHERE date_joined >= ...
.exclude(username__startswith=_) # AND NOT username LIKE _%%
.order_by(-date_joined) # ORDER BY date_joined DESC
.values(id, username, email) # SELECT id, username, email
)
Каждый метод возвращает новый QuerySet, позволяя строить сложные запросы пошагово.
Основные операции
Фильтрация (Filtering):
# Простая фильтрация
User.objects.filter(is_active=True)
# Исключение
User.objects.exclude(is_staff=True)
# Сложные условия через Q объекты
from django.db.models import Q
User.objects.filter(Q(is_staff=True) | Q(is_superuser=True))
User.objects.filter(Q(is_active=True) & ~Q(username__startswith=test))
Получение значений:
# Все объекты
users = User.objects.all()
# Первый объект
first_user = User.objects.first()
# По условию
user = User.objects.get(id=1) # Вызывает исключение, если нет
# Или None если не найдено
user = User.objects.filter(id=1).first()
Агрегация и аннотация:
from django.db.models import Count, Avg, Max
# Количество активных пользователей
User.objects.filter(is_active=True).count()
# Агрегация
stats = User.objects.aggregate(
total=Count(id),
avg_id=Avg(id)
)
# Аннотация (добавление полей)
from django.db.models import Count
users = User.objects.annotate(posts_count=Count(post))
Оптимизация запросов
Select_related — для OneToOne и ForeignKey (JOIN):
# БЕЗ оптимизации: N+1 problem
posts = Post.objects.all()
for post in posts:
print(post.author.username) # N запросов к БД
# С оптимизацией: 1 JOIN запрос
posts = Post.objects.select_related(author)
for post in posts:
print(post.author.username) # уже в памяти
Prefetch_related — для ManyToMany и обратных ForeignKey:
users = User.objects.prefetch_related(post_set)
for user in users:
for post in user.post_set.all(): # уже в памяти
print(post.title)
Материализация QuerySet
QuerySet не выполняется до одного из этих действий:
qs = User.objects.filter(is_active=True)
# Материализация:
list(qs) # Преобразование в список
for user in qs: # Итерация
user = qs.first() # Получение первого элемента
qs.count() # Подсчёт
qs.exists() # Проверка существования
qs[0] # Индексирование
Кешерование QuerySet
qs = User.objects.filter(is_active=True)
list(qs) # Первый доступ — выполняется SQL, результат кеширует
for user in qs: # Второй доступ — использует кеш, без SQL
print(user.username)
Заключение
Джанго ORM предоставляет выразительный API для построения SQL запросов на Python. Ключевые концепции: ленивое вычисление QuerySet, цепочка методов для построения условий, и методы оптимизации (select_related, prefetch_related) для избежания N+1 проблемы.