django: cómo hacer que la consulta no se ejecute de forma perezosa?
Tengo un problema con la ejecución diferida de la consulta en mi método personalizado del Manager. En él, quiero separar la consulta por las opciones de CharField del modelo y retornar dict[elección, QuerySet].
Parte del archivo model.py:
...
PRODUCT_STATUS = [
('pn', 'Zaplanowane'),
('ga', 'W trakcie (Przeglądam)'),
('rv', 'Powtórka'),
('ac', 'Zakończone'),
('ab', 'Porzucone'),
('pp', 'Wstrzymane'),
]
class ExtendedManager(models.Manager):
def separado_por_estado(self, tipo_de_producto):
query = super().get_queryset().all()
dict_ = {}
for status in PRODUCT_STATUS:
dict_.update({status[1]: query.filter(status=status[0]).all()})
return dict_
...
Parte del archivo views.py con el uso del manager:
...
class ProductListView(ContextMixin, View):
template_name = 'miLista/miLista.html'
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
product = kwargs.get('product')
if product not in {'film', 'game', 'series', 'book'}:
raise Http404
context = self.get_context_data()
context['title'] = f'Lista {product}'
context['dict_queryset'] = Product.objects.separado_por_estado(product)
return render(request, self.template_name, context)
...
El resultado de la barra de herramientas de depuración de Django está aquí: aquí
El problema es que la consulta se ejecuta de manera diferida en el manager, pero en las plantillas ya se ejecuta completamente para cada elemento de PRODUCT_STATUS por separado. ¿Cómo se puede optimizar para que se ejecute solo una vez?
Lamento mucho si estoy utilizando incorrectamente el término “diferido”.
davy.ai
El problema aquí es que la consulta se evalúa por separado para cada elemento en
PRODUCT_STATUS
al llamar aquery.filter(status=status[0]).all()
en el métodoseparated_by_status
.Una posible solución es utilizar
prefetch_related
para obtener todos los objetos relacionados en una única consulta, y luego filtrarlos segúnstatus
.Aquí tienes una versión actualizada del método
separated_by_status
que debería funcionar mejor:Aquí estoy usando
select_related
para obtener el objetoCategory
relacionado para cadaProduct
en una única consulta, yprefetch_related
para obtener cualquier objetoTag
relacionado en otra consulta.Luego, estoy filtrando la consulta por cada
status
, y almacenando la consulta de resultados en el diccionariodict
con elstatus
como clave.Esto debería resultar en una sola consulta para obtener todos los objetos
Product
, y luego el filtrado se realiza en Python en lugar de en la base de datos, lo que debería ser más rápido.Ten en cuenta que estoy utilizando
dict(PRODUCT_STATUS)
para convertir la lista de tuplas en un diccionario, de modo que pueda utilizarstatus
como clave directamente, en lugar destatus[1]
.