Класс Exists
Класс Exists применяется в составе выражений annotate или filter для создания подзапросов, проверяющих существование записей в связанных моделях. В качестве аргумента принимает объект Subquery или любой другой подзапрос. Результатом выполнения является булево значение - True, если подзапрос возвращает хотя бы одну запись, и False в противном случае. Это особенно полезно для фильтрации записей на основе наличия связанных данных без необходимости извлекать сами данные.
Синтаксис
from django.db.models import Exists, OuterRef
# Базовый синтаксис
Exists(Subquery)
# Пример использования с аннотацией
Model.objects.annotate(
has_related=Exists(RelatedModel.objects.filter(field=OuterRef('pk')))
)
Пример
Давайте аннотируем статьи флагом наличия комментариев:
from django.db.models import Exists, OuterRef
from myapp.models import Article, Comment
articles = Article.objects.annotate(
has_comments=Exists(Comment.objects.filter(article=OuterRef('pk')))
)
for article in articles:
print(f"{article.title}: {article.has_comments}")
Результат выполнения кода:
"article 1: True"
"article 2: False"
"article 3: True"
Пример
Давайте отфильтруем только те статьи, у которых есть хотя бы один комментарий с рейтингом выше 4:
from django.db.models import Exists, OuterRef, Q
from myapp.models import Article, Comment
articles_with_good_comments = Article.objects.filter(
Exists(Comment.objects.filter(
article=OuterRef('pk'),
rating__gte=4
))
)
for article in articles_with_good_comments:
print(article.title)
Результат выполнения кода:
"article 1"
"article 3"
Пример
Давайте отфильтруем авторов, у которых есть статьи, опубликованные в текущем году:
from django.db.models import Exists, OuterRef
from myapp.models import Author, Article
from datetime import date
current_year = date.today().year
authors_with_articles = Author.objects.filter(
Exists(Article.objects.filter(
author=OuterRef('pk'),
published_at__year=current_year
))
)
for author in authors_with_articles:
print(author.name)
Результат выполнения кода:
"John Doe"
"Jane Smith"