Класс Exists

Класс Exists применяется в составе выражений annotate или filter для создания подзапросов, проверяющих существование записей в связанных моделях. В качестве аргумента принимает объект Subquery или любой другой подзапрос. Результатом выполнения является булево значение - True, если подзапрос возвращает хотя бы одну запись, и False в противном случае. Это особенно полезно для фильтрации записей на основе наличия связанных данных без необходимости извлекать сами данные.

Синтаксис

pythonfrom django.db.models import Exists, OuterRef

# Базовый синтаксис
Exists(Subquery)

# Пример использования с аннотацией
Model.objects.annotate(
  has_related=Exists(RelatedModel.objects.filter(field=OuterRef('pk')))
)

Пример

Давайте аннотируем статьи флагом наличия комментариев:

pythonfrom 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}")

Результат выполнения кода:

python"article 1: True"
"article 2: False"
"article 3: True"

Пример

Давайте отфильтруем только те статьи, у которых есть хотя бы один комментарий с рейтингом выше 4:

pythonfrom 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)

Результат выполнения кода:

python"article 1"
"article 3"

Пример

Давайте отфильтруем авторов, у которых есть статьи, опубликованные в текущем году:

pythonfrom 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)

Результат выполнения кода:

python"John Doe"
"Jane Smith"

Смотрите также

  • класс Subquery,
    который используется для создания подзапросов
  • класс OuterRef,
    который ссылается на внешний запрос в подзапросах
  • метод annotate,
    который добавляет вычисляемые поля к QuerySet
  • метод filter,
    который фильтрует QuerySet на основе заданных условий