2011-08-09 9 views
8

Me sorprende que esta pregunta aparentemente aún no exista. Si lo hace, ayúdame a encontrarlo.Anotación condicional de Django

Quiero usar anotar (Recuento) y orden_por, pero no quiero contar todas las instancias de un objeto relacionado, solo aquellas que cumplen un determinado criterio.

A saber, para tener una lista de tragos por el número de cocos verdes que han realizado:

swallow.objects.annotate(num_coconuts=Count('coconuts_carried__husk__color = "green"').order_by('num_coconuts') 

Respuesta

8

Este debe ser el camino correcto.

swallow.objects.filter(
    coconuts_carried__husk__color="green" 
).annotate(
    num_coconuts=Count('coconuts_carried') 
).order_by('num_coconuts') 

Tenga en cuenta que cuando filtra por un campo relacionado, en SQL sin formato se traduce como UNIÓN IZQUIERDA más un DÓNDE. Al final, la anotación actuará en el conjunto de resultados, que contiene solo las filas relacionadas que se seleccionan del primer filtro.

+0

De hecho, este parece funcionar, pero por razones que usted señala, es totalmente contrario a la intuición. Esperaría que este conjunto de preguntas me diera todas las golondrinas que alguna vez hayan llevado al menos un coco verde, ordenado por el número total de cocos transportados, independientemente del color. – jMyles

+1

@jMyles: la documentación señala que esto depende del [orden de las cláusulas de anotación y filtro] (https://docs.djangoproject.com/en/1.3/topics/db/aggregation/#order-of-annotate- y -filtrar-cláusulas) - al revés, se comportará como usted describe. –

+2

¿Qué sucede si quiere incluir las golondrinas que no llevan cocos verdes? –

3

Para Django> = 1.8:

from django.db.models import Sum, Case, When, IntegerField 

swallow.objects.annotate(
    num_coconuts=Sum(Case(
     When(coconuts_carried__husk__color="green", then=1), 
     output_field=IntegerField(), 
    )) 
).order_by('num_coconuts')