Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между filter и Deferred в Django ORM
Это фундаментальная разница в том, как Django ORM строит и выполняет SQL запросы. Понимание этого различия критично для написания оптимальных запросов к базе данных.
Filter — условия WHERE для выборки данных
filter() — это метод для фильтрации записей по определённым условиям. Он создаёт SQL WHERE часть запроса.
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
email = models.EmailField()
# filter() создаёт WHERE условие
users = User.objects.filter(age__gte=18)
# SELECT * FROM users WHERE age >= 18;
# Можно объединить несколько filter
users = User.objects.filter(age__gte=18).filter(name__startswith='A')
# SELECT * FROM users WHERE age >= 18 AND name LIKE 'A%';
# exclude() — это инверсия filter
users = User.objects.exclude(age__lt=18)
# SELECT * FROM users WHERE age >= 18; (эквивалентно)
Deferred — отложенная загрузка полей
Deferred — это техника для оптимизации запросов путём загрузки только нужных полей из БД, а остальные загружаются позже при обращении к ним.
# Без defer — загружает все поля
users = User.objects.all() # SELECT * FROM users;
# С defer — загружает только нужные поля
users = User.objects.defer('email', 'bio') # SELECT id, name, age FROM users;
# При обращении к email — новый запрос
for user in users:
print(user.name) # В памяти, нет запроса
print(user.email) # Запрос к БД! SELECT email FROM users WHERE id = 123;
Ключевые отличия
| Аспект | filter | Deferred |
|---|---|---|
| Назначение | Фильтрация записей (WHERE) | Оптимизация полей (SELECT) |
| SQL часть | WHERE условие | SELECT список полей |
| Количество записей | Уменьшает количество строк | Не влияет на количество |
| Количество полей | Не влияет (выбирает все) | Уменьшает количество колонок |
| Ленивость | QuerySet ленивый | Очень ленивый |
| Типичное использование | Поиск, сортировка, фильтрация | Экономия памяти и трафика |
Практические примеры filter
Простая фильтрация:
# Точное совпадение
User.objects.filter(name='Alice')
# SELECT * FROM users WHERE name = 'Alice';
# Сравнение
User.objects.filter(age__gt=18) # age > 18
User.objects.filter(age__gte=18) # age >= 18
User.objects.filter(age__lt=18) # age < 18
User.objects.filter(age__lte=18) # age <= 18
# Содержит подстроку
User.objects.filter(name__icontains='alice') # case-insensitive
# IN оператор
User.objects.filter(age__in=[18, 19, 20])
# SELECT * FROM users WHERE age IN (18, 19, 20);
# Диапазон дат
from datetime import date
User.objects.filter(created__date__range=['2024-01-01', '2024-12-31'])
# NULL проверка
User.objects.filter(bio__isnull=True) # Где bio NULL
Сложная фильтрация с Q объектами:
from django.db.models import Q
# OR условие
User.objects.filter(Q(age=18) | Q(age=19))
# SELECT * FROM users WHERE age = 18 OR age = 19;
# AND условие
User.objects.filter(Q(age__gte=18) & Q(name__startswith='A'))
# NOT условие
User.objects.filter(~Q(age__lt=18))
# SELECT * FROM users WHERE NOT (age < 18);
# Сложные условия
User.objects.filter(
Q(age__gte=18) & (Q(name='Alice') | Q(name='Bob'))
)
# SELECT * FROM users WHERE age >= 18 AND (name = 'Alice' OR name = 'Bob');
Практические примеры Deferred
Когда нужна только часть полей:
# Загружаем только name и age, не загружаем bio (большой текст)
users = User.objects.defer('bio').all()
for user in users:
print(user.name) # OK, в памяти
print(user.age) # OK, в памяти
print(user.bio) # ❌ Дополнительный запрос!
Противоположное — only() загружает только нужные поля:
# Загружаем ТОЛЬКО name и age
users = User.objects.only('name', 'age').all()
for user in users:
print(user.name) # OK
print(user.age) # OK
print(user.email) # ❌ Дополнительный запрос к БД
Сравнение defer и only:
# Если много полей, defer удобнее
User.objects.defer('large_text_field', 'another_large_field', 'third_large')
# Если нужна одна-две поля, only удобнее
User.objects.only('name', 'email')
Когда использовать что
Использовать filter когда:
- Нужны только определённые записи (WHERE)
- Сортировка и поиск
- Объединение с другими таблицами (JOIN)
# Получить активных пользователей старше 18
active_adults = User.objects.filter(
is_active=True,
age__gte=18
).order_by('-created_at')
Использовать defer/only когда:
- Есть большие текстовые поля (TextField, JSONField)
- Нужно уменьшить объём данных из БД
- Много записей (экономия памяти и трафика)
# Получить список пользователей, но не загружать большое описание
users = User.objects.defer('bio', 'large_photo').all()
# Если нужно значение bio, используй select_related
users = User.objects.filter(bio__isnull=False).values_list('name', 'bio')
Комбинирование filter и Deferred
Оптимальный запрос:
# Фильтруем по условию И выбираем только нужные поля
users = User.objects.filter(
is_active=True,
age__gte=18
).defer('large_bio_field').order_by('-created_at')
# SQL примерно:
# SELECT id, name, age, created_at FROM users
# WHERE is_active = 1 AND age >= 18
# ORDER BY created_at DESC;
Отладка запросов
from django.db import connection
from django.test.utils import CaptureQueriesContext
# Посмотреть SQL запрос
users_qs = User.objects.filter(age__gte=18)
print(users_qs.query) # SELECT ... WHERE age >= 18;
# Подсчитать количество запросов
with CaptureQueriesContext(connection) as queries:
users = list(User.objects.defer('bio').all())
for user in users:
print(user.bio) # Каждое обращение = новый запрос!
print(len(queries)) # Количество запросов
for query in queries:
print(query['sql']) # Каждый SQL запрос
Производительность
Пример: 1000 пользователей, каждый с bio 10KB
# ❌ Неоптимально: загружает 10MB данных
users = User.objects.all() # SELECT * — загружает bio для всех
# ✅ Оптимально: загружает 100KB
users = User.objects.defer('bio').all()
# Если потом всё-таки нужна bio, это 1000 запросов
# Лучше использовать select_related для связей
Итоговая рекомендация
- filter() — это WHERE, для выбора КАКИХ записей нужны
- Deferred (defer/only) — это оптимизация SELECT, для выбора КАКИХ ПОЛЕЙ нужны
- Сочетай оба: фильтруй записи AND выбирай нужные поля
- Не забывай про select_related и prefetch_related для оптимизации связанных таблиц