← Назад к вопросам

Как строится запрос в Django?

1.0 Junior🔥 131 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как строится запрос в 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 проблемы.

Как строится запрос в Django? | PrepBro