Django: выполняет ли prefetch_related() поиск обратной связи?

Я пробовал prefetch_related() в django 1.4 из магистрали и не могу выполнить предварительную выборку обратного поиска.

Мои упрощенные модели (у каждой книги много цен):

class Book(models.Model):
    # some fields

class Price(models.Model):
    book = models.ForeignKey(Book)

Мой запрос представления:

books = Book.objects.prefetch_related('price')

Затем я получил сообщение AttributeError:

AttributeError: Cannot find 'price' on Book object, 'price' is an invalid parameter to prefetch_related()

Как заставить это работать? Спасибо.


person Tianissimo    schedule 07.02.2012    source источник
comment
книги = Book.objects.prefetch_related('price_set')   -  person moriesta    schedule 08.04.2013
comment
@Jonathanz: вы должны указать свой комментарий как принятый ответ, т.е. prefetch_related('price_set')   -  person user    schedule 25.04.2014


Ответы (2)


Определите родственное имя:

class Price(models.Model):
    book = models.ForeignKey(Book, related_name='prices')

а затем используйте его:

books = Book.objects.prefetch_related('prices')
person Jan Pöschko    schedule 07.02.2012
comment
Ваш ответ напоминает мне о FOO_set, поэтому исправление также может быть .prefetch_related('price_set'). Кстати, большое спасибо - person Tianissimo; 07.02.2012
comment
Я не могу воспроизвести это в оболочке. Все еще делает отдельные запросы, я ожидал объединения. - person pdvyas; 30.05.2013
comment
Привет! Я также пробовал это, но, как сказал @pdvyas, есть отдельные запросы. Это не делает соединение... - person Anton; 01.07.2013
comment
prefetch_related не выполняет соединения, он просто собирает идентификаторы связанных объектов, а затем извлекает эти объекты в одном запросе и генерирует эти «соединения» внутри Python. См.: docs.djangoproject .com/en/dev/ref/models/querysets/ - person aherok; 28.08.2013
comment
@jan-pöschko, кажется (более простой) альтернативой определению related_name использовать имя price_set для ссылки на отношение. Я добавил ответ, описывающий это, но, возможно, было бы неплохо сослаться на мой ответ в вашем (принятом) ответе или включить мой текст в свой? - person Matthijs Kooijman; 15.02.2018

Если вы не определили related_name для отношения, к обратному отношению добавляется _set. Это имеет место при доступе к обратному отношению из объекта (например, some_book.price_set.all()), но это также работает для prefetch_related:

books = Book.objects.prefetch_related('price_set')

Обратите внимание, что это отличается от фильтра, который действительно принимает имя другой модели без _set (например, Books.objects.filter(price__currency='EUR')).

Вышеупомянутое было протестировано с 1.11.8 (не на этом конкретном коде, а на моем собственном аналогичном коде).

Кроме того, вы можете добавить related_name, как показано выше у Яна Пёшко.

person Matthijs Kooijman    schedule 15.02.2018