← Назад к вопросам
Как реализуется логика "или" в querySet в Django?
1.8 Middle🔥 221 комментариев
#Django#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Логика "ИЛИ" в Django QuerySet
Для реализации логики "или" (OR) в Django ORM используется объект Q. Это мощный инструмент для построения сложных условий в querySet.
1. Основной синтаксис с Q
from django.db.models import Q
from myapp.models import Article
# Найти статьи, где title содержит "Django" ИЛИ content содержит "Python"
result = Article.objects.filter(
Q(title__contains="Django") | Q(content__contains="Python")
)
# SQL эквивалент:
# SELECT * FROM article WHERE title LIKE '%Django%' OR content LIKE '%Python%'
2. Комбинирование AND и OR
OR (|) имеет приоритет над AND (&):
# (title contains "Django" OR author is John) AND published is True
result = Article.objects.filter(
(Q(title__contains="Django") | Q(author__name="John")),
published=True
)
# SQL:
# SELECT * FROM article
# WHERE (title LIKE '%Django%' OR author_id = john_id) AND published = true
Использование & для AND:
result = Article.objects.filter(
Q(title__contains="Django") & Q(author__name="John")
)
# SQL: WHERE title LIKE '%Django%' AND author_id = john_id
3. Отрицание (NOT) с ~
# Статьи, которые НЕ содержат "спам" И НЕ неопубликованы
result = Article.objects.filter(
~Q(title__contains="spam"),
~Q(published=False)
)
# SQL:
# SELECT * FROM article
# WHERE title NOT LIKE '%spam%' AND published = true
4. Сложные условия
# Найти статьи:
# (категория = "Tech" И (автор="John" ИЛИ автор="Jane"))
# ИЛИ (опубликовано В течение последних 7 дней)
from datetime import timedelta
from django.utils import timezone
result = Article.objects.filter(
Q(
Q(category="Tech") & (Q(author__name="John") | Q(author__name="Jane"))
) |
Q(published_date__gte=timezone.now() - timedelta(days=7))
)
5. Практические примеры
Поиск пользователей по email или username:
from django.contrib.auth.models import User
user = User.objects.get(
Q(email="test@example.com") | Q(username="testuser")
)
Фильтрация товаров в интернет-магазине:
# Товары дорогие (>1000) И (в наличии ИЛИ доступны для заказа)
products = Product.objects.filter(
Q(price__gt=1000),
Q(in_stock=True) | Q(available_for_order=True)
)
Поиск комментариев:
# Комментарии (от администратора ИЛИ спам) И опубликованы
comments = Comment.objects.filter(
(Q(author__is_staff=True) | Q(is_spam=True)),
published=True
)
6. Динамическое построение Q
Часто нужно динамически собирать условия:
from django.db.models import Q
def search_articles(keywords=None, authors=None, published_only=False):
query = Q() # Начинаем с пустого Q
# Добавляем условия по ключевым словам (OR)
if keywords:
for keyword in keywords:
query |= Q(title__icontains=keyword) | Q(content__icontains=keyword)
# Добавляем условия по авторам (OR)
if authors:
author_query = Q()
for author in authors:
author_query |= Q(author__name=author)
query &= author_query
# Фильтр по опубликованности (AND)
if published_only:
query &= Q(published=True)
return Article.objects.filter(query)
# Использование
articles = search_articles(
keywords=["Django", "Python"],
authors=["John", "Jane"],
published_only=True
)
7. Исключение (exclude) с Q
# Исключить статьи, которые либо спам, либо неопубликованы
result = Article.objects.exclude(
Q(is_spam=True) | Q(published=False)
)
# Эквивалентно:
result = Article.objects.filter(
~(Q(is_spam=True) | Q(published=False))
)
# SQL: WHERE NOT (is_spam = true OR published = false)
# => WHERE is_spam = false AND published = true
8. Оптимизация с exists() и count()
# Найти авторов, у которых ЕСТЬ (опубликованные статьи ИЛИ спам)
from django.db.models import Exists, OuterRef
result = Article.objects.filter(
Q(published=True) | Q(is_spam=True)
).values('author').distinct()
# Или с Exists для более сложных случаев:
spam_or_published = Article.objects.filter(
author=OuterRef('pk'),
Q(published=True) | Q(is_spam=True)
)
authors_with_spam_or_published = User.objects.filter(
Exists(spam_or_published)
)
9. Производительность
Плохо — выполнит 2 отдельных запроса и объединит в памяти:
result1 = Article.objects.filter(title__contains="Django")
result2 = Article.objects.filter(author__name="John")
result = result1 | result2 # Union в памяти (медленно)
Хорошо — один SQL запрос:
result = Article.objects.filter(
Q(title__contains="Django") | Q(author__name="John")
) # Один SELECT с OR в WHERE
10. Проверка SQL с explain()
# Django 3.1+
query = Article.objects.filter(
Q(title__contains="Django") | Q(published=True)
)
print(query.explain()) # Вывести план выполнения
Итоговая таблица операций
Операция | Синтаксис | Значение | SQL
-----------|----------------|------------------|-------------------
ILI (OR) | Q1 | Q2 | Q1 ИЛИ Q2 | WHERE ... OR ...
I (AND) | Q1 & Q2 | Q1 И Q2 | WHERE ... AND ...
NOT | ~Q1 | НЕ Q1 | WHERE NOT (...)
Исключить | .exclude(Q) | НЕ Q | WHERE NOT (...)
Правила использования
- Используй Q для OR условий — filter() по умолчанию работает как AND
- Правильно расставляй скобки — приоритет операций важен
- Избегай дублирования — используй Exists() для сложных условий
- Проверяй SQL — используй str(query.query) или .explain()
- Оптимизируй запросы — используй select_related() / prefetch_related()
Q объекты — это ключ к мощным и эффективным фильтрам в Django ORM.