es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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”.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema aquí es que la consulta se evalúa por separado para cada elemento en PRODUCT_STATUS al llamar a query.filter(status=status[0]).all() en el método separated_by_status.

    Una posible solución es utilizar prefetch_related para obtener todos los objetos relacionados en una única consulta, y luego filtrarlos según status.

    Aquí tienes una versión actualizada del método separated_by_status que debería funcionar mejor:

    class ExtendedManager(models.Manager):
        def separated_by_status(self, product_type):
            queryset = super().get_queryset().all().select_related('category').prefetch_related('tags')
            dict_ = {}
            for status in dict(PRODUCT_STATUS):
                filtered = queryset.filter(status=status)
                dict_[status] = filtered
            return dict_
    

    Aquí estoy usando select_related para obtener el objeto Category relacionado para cada Product en una única consulta, y prefetch_related para obtener cualquier objeto Tag relacionado en otra consulta.

    Luego, estoy filtrando la consulta por cada status, y almacenando la consulta de resultados en el diccionario dict con el status 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 utilizar status como clave directamente, en lugar de status[1].

Comments are closed.