2010-06-28 13 views
5

He buscado por todos lados una respuesta a esto, pero no pude encontrar nada. Tal vez esta es solo una pregunta estúpida o muy complicada. Aquí está:Anotar un conjunto de preguntas con la diferencia de fecha promedio? (django)

Digamos que mi modelo es la siguiente (pseudo código Django):

Event 
    type = ForeignKey(EventType) 
    name = CharField 
    date_start = DateField 
    date_end = DateField 

EventType 
    name = CharField 

Lo que yo quiero saber es el tiempo medio de duración para cada tipo de evento. Lo que hago ahora es calcular la duración promedio cada vez que se crea un nuevo evento (método save) y tenerlo almacenado en una columna average_duration en EventType. El problema con este enfoque es que no puedo responder preguntas como "¿cuál fue el tiempo de duración promedio para eventos de tipo X, durante el año Y". Entonces, en lugar de agregar más columnas para responder preguntas como estas, preferiría que se haga en "tiempo real".

¿Se puede hacer esto anotando el conjunto de preguntas? Primero tendría que obtener las diferencias de fecha para cada tipo de evento, luego presentar su promedio, y luego anotar el conjunto de preguntas del evento con ese promedio, supongo.

Respuesta

1

Creo que su mejor opción es crear una vista SQL con la columna date_end - date_start, crear un modelo django en esta vista y luego podrá consultar la vista y anotarla como desee. He hecho esto con modelos similares a los tuyos y tal vez podría extraer algún código interesante para ti si lo necesitas.

+0

Sí si se pudiera proporcionar algunos ejemplos de código que sería genial, gracias –

1

Tendrá que crear un conjunto de consultas con el método extra añadir la diferencia de fechas para cada fila

A continuación, utilice el método aggregate para calcular la media de la columna se agregó:

Tenga cuidado sin embargo , este método es lento y no se escalará. Almacenar el valor calculado en event_type es su mejor opción.

2

Yo sugeriría que almacene la duración del evento como una columna:

event_duration = models.IntegerField() 
... 

def __init__(self, *args, **kwargs): 
    super(Event, self).__init__(*args, **kwargs) 
    self.update_event_duration() 


def save(self, **kwargs): 
    self.update_event_duration() 
    super(Event, self).save(*args, **kwargs) 

A continuación, puede utilizar esta biblioteca: http://code.google.com/p/django-cube/ para calcular el promedio de varias dimensiones diferentes (año, tipo, o de otro tipo):

>>> def my_avg(queryset): 
... return queryset.aggregate(Avg("event_duration"))["event_duration__avg"] 

>>> c = Cube(["date_start__year", "type"], Event.objects.all(), my_avg) 

Utilice el cubo de la siguiente manera:

>>> c.measure(date_start__year=1999, type=event_type2) 
123.456 

O puede obtener todos los promedios de todos los años:

>>> c.measure_dict("date_start__year") 
{1984: {'measure': 111.789}, 1985: {'measure': 234.666}, ...} 

o por tipo de año/evento:

>>> c.measure_dict("date_start__year", "type") 
{ 
    1984: {eventtype1: {'measure': 111.789}, eventtype2: {'measure': 234.666}, ...}, 
    1985: {eventtype1: {'measure': 122.79}, eventtype2: {'measure': 233.444}, ...}, 
    ... 
} 
+0

No sé pero esta solución parece romper el ORM para calcular un valor, sin embargo, creo que Django aún no lo admite. –

18

Apenas una actualización. En Django 1.8 es posible hacer:

from django.db.models import F, ExpressionWrapper, fields 

duration = ExpressionWrapper(F('date_end') - F('date_start'), output_field=fields.DurationField()) 

events_with_duration = Event.objects.annotate(duration=duration) 

después de lo cual se puede ejecutar consultas como:

events_with_duration.filter(duration_gt=timedelta(days=10)) 
+1

¿No debería ser date_end - date_start? –

+0

@AndreBossard, tienes toda la razón. gracias – ryuusenshi

+1

Prueba en Django 1.8, esto no parece funcionar cuando se aplica a las funciones agregadas (por ejemplo, Event.objects.annotate (duration = duration) .aggregrate (Avg ('duration'))) –

Cuestiones relacionadas