2012-08-24 9 views
8

En la siguiente configuración, me gustaría un QuerySet con una lista de proyectos, cada uno anotado con la suma de todas sus duraciones (como tasks_duration) y la suma de todas sus tareas ' duraciones de la subtarea (como subtasks_duration). Mis modelos (simplificado) se ven así:multiple annotate Sum terms yields inflated answer

class Project(models.Model): 
    pass 

class Task(models.Model): 
    project = models.ForeignKey(Project) 
    duration = models.IntegerField(blank=True, null=True) 

class SubTask(models.Model): 
    task = models.ForeignKey(Task) 
    duration = models.IntegerField(blank=True, null=True) 

hago mis QuerySet así:

Projects.objects.annotate(tasks_duration=Sum('task__duration'), subtasks_duration=Sum('task__subtask__duration')) 

relacionados con el comportamiento se explica en Django annotate() multiple times causes wrong answers recibo una tasks_duration que es mucho mayor de lo que debería ser. Las cláusulas de anotaciones múltiples (Sum()) producen múltiples uniones internas izquierdas en el SQL resultante. Con solo un único término de anotación (Sum()) para tasks_duration, el resultado es correcto. Sin embargo, me gustaría tener tanto tasks_duration como subtasks_duration.

¿Cuál sería una forma adecuada de hacer esta consulta? Tengo una solución de trabajo que lo hace por proyecto, pero eso es inusualmente lento. También tengo algo similar que funciona con una llamada extra(), pero realmente me gustaría saber si lo que quiero es posible con Django puro.

+0

¿Usted intentó 'tasks_duration = Sum ('task__duration', distinto = True), subtasks_duration = Sum ('task__subtask__duration', distinto = True)' como mencionado en la otra pregunta que vinculó? – jpic

+0

Eso solo servirá para sumar valores de duración distintos, que no es lo que quiero. Por curiosidad lo intenté, todavía produce los mismos valores incorrectos. (las duraciones varían) –

+0

¿Alguna vez encontró una solución para esto? Estoy tratando de anotar una suma y un conteo en un conjunto de preguntas, y la suma se sigue multiplicando ... – StephenTG

Respuesta

1

Recibo este error también. Exacto mismo código. Funciona si hago la agregación por separado, pero una vez que intento obtener ambas sumas al mismo tiempo, una de ellas obtiene un factor 2 más alto y la otra un factor 3.

No tengo idea de por qué Django se comporta así camino. He archivado un informe de error aquí: https://code.djangoproject.com/ticket/19011 Puede que también le interese seguirlo.

+0

No es realmente un error en Django, sino un problema de la complejidad de hacer estas consultas agregadas a la base de datos. Incluso si escribió el SQL usted mismo, tendría que resolver este problema. – benjaoming

+1

Enlace al informe de error relevante: https://code.djangoproject.com/ticket/10060 – benjaoming

+0

Este error aún no se ha solucionado. – sobolevn

1

El error se reporta here pero aún no está resuelto en Django 1.11. El problema está relacionado con unir dos tablas en relaciones inversas. Observe que el parámetro distinto funciona bien para el recuento pero no para la suma. Así que usted puede utilizar un truco y escribir un ORM, como a continuación:

Projects.objects.annotate(
     temp_tasks_duration=Sum('task__duration'), 
     temp_subtasks_duration=Sum('task__subtask__duration'), 
     tasks_count=Count('task'), 
     tasks_count_distinct=Count('task', distinct=True), 
     task_subtasks_count=Count('task__subtask'), 
     task_subtasks_count_distinct=Count('task__subtask', distinct=True), 
).annotate(
     tasks_duration=F('temp_tasks_duration')*F('tasks_count_distinct')/F('tasks_count'), 
     subtasks_duration=F('temp_subtasks_duration')*F('subtasks_count_distinct')/F('subtasks_count'), 
)