Prefetch_related для нескольких уровней
Если мои модели выглядят так:
class Publisher(models.Model):
pass
class Book(models.Model):
publisher = models.ForeignKey(Publisher)
class Page(models.Model):
book = models.ForeignKey(Book)
и я хотел бы получить запрос для Publisher
я do Publisher.object.all()
.
Если вы хотите убедиться в предварительной выборке, я могу сделать:
Publisher.objects.all().prefetch_related('book_set')`
Мои вопросы:
- Есть ли способ сделать эту предварительную выборку с помощью
select_related
или
я должен использовать prefetch_related
?
- Есть ли способ предварительной выборки
page_set
? Это не работает:
Publisher.objects.all().prefetch_related('book_set', 'book_set_page_set')
Ответы
Ответ 1
-
Нет, вы не можете использовать select_related
для обратного отношения. select_related
выполняет объединение SQL, поэтому одной записи в главном запросе требуется указать только одно в связанной таблице (поля ForeignKey
или OneToOne
). prefetch_related
фактически выполняет полностью отдельный второй запрос, кэширует результаты, затем "присоединяет" его к набору запросов в python. Поэтому это необходимо для полей ManyToMany
или reverse ForeignKey
.
-
Вы пробовали два символа подчеркивания, чтобы сделать предварительные выборки на нескольких уровнях? Вот так: Publisher.objects.all().prefetch_related('book_set', 'book_set__page_set')
Ответ 2
Так как Django 1.7, экземпляры класса django.db.models.Prefetch
могут использоваться как аргумент .prefetch_related
. Prefetch
конструктор объекта имеет аргумент queryset
, который позволяет задавать вложенные множественные предварительные выборки следующим образом:
Project.objects.filter(
is_main_section=True
).select_related(
'project_group'
).prefetch_related(
Prefetch(
'project_group__project_set',
queryset=Project.objects.prefetch_related(
Prefetch(
'projectmember_set',
to_attr='projectmember_list'
)
),
to_attr='project_list'
)
)
Он сохраняется в атрибутах с суффиксом _list
, потому что я использую ListQuerySet
для обработки результатов предварительной выборки (фильтр/порядок).