Solución:
En Django 1.6 y versiones anteriores, no es posible evitar las consultas adicionales. los prefetch_related
llamar efectivamente almacena en caché los resultados de a.photoset.all()
para cada álbum del conjunto de consultas. Sin embargo, a.photoset.filter(format=1)
es un conjunto de consultas diferente, por lo que generará una consulta adicional para cada álbum.
Esto se explica en el prefetch_related
docs. los filter(format=1)
es equivalente a filter(spicy=True)
.
Tenga en cuenta que podría reducir el número de consultas filtrando las fotos en Python en su lugar:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
somePhotos = [p for p in a.photo_set.all() if p.format == 1]
En Django 1.7, hay un Prefetch()
objeto que le permite controlar el comportamiento de prefetch_related
.
from django.db.models import Prefetch
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related(
Prefetch(
"photo_set",
queryset=Photo.objects.filter(format=1),
to_attr="some_photos"
)
)
for a in someAlbums:
somePhotos = a.some_photos
Para obtener más ejemplos de cómo utilizar el Prefetch
objeto, ver el prefetch_related
docs.
De los documentos:
… como siempre con QuerySets, cualquier método encadenado posterior que implique una consulta de base de datos diferente ignorará los resultados previamente almacenados en caché y recuperará los datos utilizando una consulta de base de datos nueva. Entonces, si escribe lo siguiente:
pizzas = Pizza.objects.prefetch_related('toppings')
[list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
… entonces el hecho de que pizza.toppings.all () se haya obtenido previamente no le ayudará; de hecho, perjudica el rendimiento, ya que ha realizado una consulta de base de datos que no ha utilizado. ¡Utilice esta función con precaución!
En su caso, “a.photo_set.filter (format = 1)” se trata como una consulta nueva.
Además, “photo_set” es una búsqueda inversa, implementada a través de un administrador diferente.