queryset prefetch_related inner examples django django-queryset django-orm

prefetch_related - filter django



prefetch_related para niveles mĂșltiples (2)

Si mis modelos parecen:

class Publisher(models.Model): pass class Book(models.Model): publisher = models.ForeignKey(Publisher) class Page(models.Model): book = models.ForeignKey(Book)

y me gustaría obtener el queryset para Publisher que hago Publisher.object.all() . Si luego quiero asegurarme de que prefetch puedo hacer:

Publisher.objects.all().prefetch_related(''book_set'')`

Mis preguntas son:

  1. ¿Hay alguna manera de realizar esta búsqueda select_related utilizando select_related o debo usar prefetch_related ?
  2. ¿Hay una manera de prefetch el page_set ? Esto no funciona:

Publisher.objects.all().prefetch_related(''book_set'', ''book_set_page_set'')


  1. No, no puede utilizar select_related para una relación inversa. select_related realiza una unión a SQL, por lo que un solo registro en el conjunto de consultas principal debe hacer referencia a exactamente uno en la tabla relacionada (campos ForeignKey o OneToOne ). prefetch_related realidad hace una segunda consulta totalmente separada, almacena en caché los resultados, luego los "une" en el conjunto de consultas en Python. Por lo tanto, es necesario para los ManyToMany o Invertir ForeignKey .

  2. ¿Has intentado dos guiones bajos para hacer las gestiones previas de múltiples niveles? Así: Publisher.objects.all().prefetch_related(''book_set'', ''book_set__page_set'')


Desde Django 1.7, las instancias de la clase django.db.models.Prefetch se pueden usar como un argumento de .prefetch_related . Prefetch constructor de objetos de queryset tiene un argumento queryset que permite especificar los queryset múltiples niveles anidados como ese:

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

Se almacena en atributos con el sufijo _list porque uso ListQuerySet para procesar los resultados de búsqueda ListQuerySet (filtro / orden).