Usando Django rest framework 3.x y Django 1.1.10 . Tengo un modelo que representa a los usuarios. Cuando enumero a todos los usuarios accediendo a /users/ endpoint en DRF, la lista debe incluir algunos datos más relacionados con los usuarios a través de otro modelo, llamado Propietario. Cada elemento tiene un propietario y los propietarios tienen usuarios.
Hice una propiedad adicional en el modelo de usuario y solo devuelve una matriz JSON de los datos. Esto es algo que no puedo cambiar, porque es un requisito en el front-end. Tengo que devolver una cantidad total de elementos relacionados con cada usuario y hay tres recuentos diferentes que realizar para obtener los datos.
Necesito obtener múltiples conteos () de artículos en el mismo modelo pero con diferentes condiciones.
Hacer estos por separado es fácil, dos son triviales y el último es más complicado:
Item.objects.filter(owner__user=self).count() Item.objects.filter(owner__user=self, published=True).count() Item.objects.filter(Q(history__action__name='argle') | Q(history__action__name='bargle'), history__since__lte=now, history__until__gte=now, owner__user=self).count()El problema es que esto se ejecuta para todos los usuarios y hay muchos de ellos. Al final, esto genera más de 300 consultas de base de datos y me gustaría reducirlas al mínimo.
Hasta ahora se me ha ocurrido esto:
Item.objects.filter(owner__user=self)\ .aggregate(published=Count('published'), total=Count('id')) Esto agregará los dos primeros recuentos, los devolverá y solo se realizará una SELECT en la base de datos. ¿Hay alguna manera de incorporar la última llamada count() en ese mismo aggregate() ?
Intenté muchas cosas, pero parece imposible. ¿Debería simplemente escribir un SELECT personalizado y usar Item.objects.raw() ?
También noté que realizar el aggregate() y el último count() es más rápido en mi máquina de desarrollo y SQLite que en el servidor de ensayo con Postgresql, lo cual es un poco extraño, pero no es mi principal preocupación en este momento.
Dado que necesita los recuentos para cada elemento en su QuerySet, debe usar anotar en lugar de agregar, esto solo realizará 1 consulta.
La mejor manera de contar objetos relacionados en función de una condición es utilizar la agregación condicional.
User.objects.annotate( total_items=Count('items'), published=Sum(Case(When(items__published=True, then=1), output_field=IntegerField())), foo=Sum(Case(When( Q(history__action__name='argle') | Q(history__action__name='bargle'), history__since__lte=now, history__until__gte=now, then=1 ), output_field=IntegerField())) )