Класс Prefetch

Класс Prefetch применяется совместно с методом prefetch_related для расширенной настройки предварительной загрузки связанных объектов. В отличие от обычного использования prefetch_related с строковыми аргументами, Prefetch позволяет передавать собственный QuerySet для загрузки связанных данных с дополнительными условиями фильтрации, сортировки и ограничениями. Он принимает три основных параметра: lookup (имя связи), queryset (настроенный QuerySet) и to_attr (опциональное имя атрибута для сохранения результатов). Класс особенно полезен когда нужно получить не все связанные объекты, а только их часть, удовлетворяющую определенным критериям.

Синтаксис

pythonfrom django.db.models import Prefetch

Prefetch(lookup, queryset=None, to_attr=None)

Пример

Давайте предварительно загрузим только опубликованные статьи для каждого автора:

pythonfrom myapp.models import Author, Article
from django.db.models import Prefetch

# Настраиваем QuerySet для статей с фильтрацией
published_articles = Article.objects.filter(status="published")

# Используем Prefetch для загрузки только опубликованных статей
authors = Author.objects.prefetch_related(
  Prefetch("articles", queryset=published_articles)
)

for author in authors:
  print(f"{author.name}: {author.articles.count()} published articles")

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

python"John Doe: 3 published articles"
"Jane Smith: 2 published articles"
"Bob Johnson: 0 published articles"

Пример

Теперь используем параметр to_attr для сохранения предварительно загруженных объектов в отдельный атрибут:

pythonfrom myapp.models import Author, Article
from django.db.models import Prefetch

# Получаем последние 3 статьи для каждого автора
recent_articles = Article.objects.order_by("-created_at")[:3]

authors = Author.objects.prefetch_related(
  Prefetch(
    "articles",
    queryset=recent_articles,
    to_attr="recent_articles"
  )
)

for author in authors:
  for article in author.recent_articles:
    print(f"{author.name}: {article.title}")

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

python"John Doe: Advanced Django"
"John Doe: Python Basics"
"Jane Smith: Web Development"
"Bob Johnson: Database Design"

Пример

Пример с цепочкой Prefetch для вложенных связей и комбинированной фильтрации:

pythonfrom myapp.models import Author, Article, Comment
from django.db.models import Prefetch

# Настраиваем Prefetch для комментариев к статьям
recent_comments = Comment.objects.order_by("-created_at")[:5]

# Настраиваем Prefetch для статей с комментариями
articles_with_comments = Article.objects.prefetch_related(
  Prefetch("comments", queryset=recent_comments, to_attr="recent_comments")
)

# Основной запрос с вложенным Prefetch
authors = Author.objects.prefetch_related(
  Prefetch("articles", queryset=articles_with_comments)
)

for author in authors:
  for article in author.articles.all():
    print(f"{author.name} - {article.title}: {len(article.recent_comments)} comments")

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

python"John Doe - Advanced Django: 3 comments"
"John Doe - Python Basics: 2 comments"
"Jane Smith - Web Development: 1 comment"
"Bob Johnson - Database Design: 0 comments"

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

  • метод prefetch_related,
    который выполняет предварительную загрузку связанных объектов
  • метод select_related,
    который выполняет загрузку связанных объектов через JOIN
  • метод filter,
    который фильтрует QuerySet по заданным условиям
  • метод order_by,
    который сортирует QuerySet по указанным полям