Функция prefetch_related_objects

Функция prefetch_related_objects применяется к существующему списку моделей и выполняет превентивную подгрузку связанных объектов для каждого элемента списка. Это позволяет избежать проблемы "N+1 запросов", когда для каждого объекта выполняется отдельный запрос для получения связанных данных. Функция принимает список моделей и аргументы для указания связей, которые необходимо предзагрузить.

Синтаксис

pythonfrom django.db.models import prefetch_related_objects

prefetch_related_objects(objects, *lookups)

Параметры функции:

objects - итерируемый объект с моделями (QuerySet или список), для которых нужно предзагрузить связанные данные.

*lookups - один или несколько аргументов, определяющих связи для превентивной загрузки. Это могут быть строки с именами полей связи или объекты Prefetch для более тонкой настройки.

Пример

Пусть у нас есть модели для статей и их авторов. Получим все статьи и подгрузим связанных авторов для каждой статьи:

pythonfrom django.db import models
from django.db.models import prefetch_related_objects

class Author(models.Model):
  name = models.CharField(max_length=100)

class Article(models.Model):
  title = models.CharField(max_length=200)
  author = models.ForeignKey(Author, on_delete=models.CASCADE)

# Получаем все статьи
articles = list(Article.objects.all())

# Предзагружаем авторов для всех статей
prefetch_related_objects(articles, 'author')

for article in articles:
  print(f"Article: {article.title}, Author: {article.author.name}")

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

python"Article: Django basics, Author: John Doe"
"Article: Advanced ORM, Author: Jane Smith"
"Article: Web development, Author: John Doe"

Пример

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

pythonfrom django.db import models
from django.db.models import prefetch_related_objects

class Profile(models.Model):
  bio = models.TextField()
  author = models.OneToOneField(Author, on_delete=models.CASCADE)

class Article(models.Model):
  title = models.CharField(max_length=200)
  author = models.ForeignKey(Author, on_delete=models.CASCADE)
  tags = models.ManyToManyField('Tag')

class Tag(models.Model):
  name = models.CharField(max_length=50)

# Получаем недавние статьи
articles = list(Article.objects.filter(title__icontains='django'))

# Предзагружаем авторов и профили авторов
prefetch_related_objects(articles, 'author__profile')

for article in articles:
  print(f"Article: {article.title}")
  print(f"Author: {article.author.name}")
  print(f"Bio: {article.author.profile.bio}")
  print("---")

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

python"Article: Django basics"
"Author: John Doe"
"Bio: Senior developer with 10 years of experience"
"---"
"Article: Django advanced"
"Author: Jane Smith"
"Bio: Python expert and Django core contributor"
"---"

Пример

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

pythonfrom django.db import models
from django.db.models import prefetch_related_objects, Prefetch, Q

class Comment(models.Model):
  text = models.TextField()
  article = models.ForeignKey(Article, on_delete=models.CASCADE)
  created_at = models.DateTimeField(auto_now_add=True)
  is_approved = models.BooleanField(default=True)

# Получаем статьи
articles = list(Article.objects.all())

# Создаем Prefetch объект для подгрузки только одобренных комментариев
prefetch_comments = Prefetch(
  'comment_set',
  queryset=Comment.objects.filter(is_approved=True).order_by('-created_at'),
  to_attr='approved_comments'
)

# Применяем превентивную загрузку
prefetch_related_objects(articles, prefetch_comments)

for article in articles:
  print(f"Article: {article.title}")
  print(f"Comments count: {len(article.approved_comments)}")
  for comment in article.approved_comments[:3]:
    print(f"  - {comment.text}")
  print("---")

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

python"Article: Django basics"
"Comments count: 5"
"  - Great article!"
"  - Very helpful, thanks!"
"  - Could you explain more about models?"
"---"
"Article: Advanced ORM"
"Comments count: 3"
"  - This is exactly what I needed"
"  - Excellent explanation"
"  - Helped me optimize my queries"
"---"

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

  • метод prefetch_related,
    который выполняет превентивную подгрузку связанных данных в QuerySet
  • метод select_related,
    который выполняет превентивную подгрузку данных через JOIN в SQL
  • класс Prefetch,
    который позволяет тонко настраивать превентивную загрузку данных
  • метод only,
    который ограничивает загружаемые поля модели для оптимизации запросов