2010-06-28 14 views
5

Szukałem odpowiedzi na to pytanie, ale nie mogłem nic znaleźć. Być może jest to po prostu głupie pytanie lub naprawdę trudne. Oto ona:Opisuj zestaw pytań ze średnią różnicą dat? (django)

Powiedzmy mój model jest to (pseudo django kodu):

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

EventType 
    name = CharField 

Co chcę wiedzieć jest średni czas trwania dla każdego typu zdarzenia. Teraz robię to, obliczając średni czas trwania, kiedy tworzone jest nowe zdarzenie (metoda zapisu) i które jest przechowywane w kolumnie average_duration w EventType. Problem z tym podejściem polega na tym, że nie mogę odpowiedzieć na pytania typu "jaki był średni czas trwania zdarzeń typu X, w ciągu roku Y". Zamiast więc dodawać więcej kolumn do odpowiedzi na takie pytania, wolałbym, aby było to wykonywane w "czasie rzeczywistym".

Czy można tego dokonać, dodając adnotację do zapytania? Najpierw musiałbym uzyskać różnice dat dla każdego typu zdarzenia, następnie wymyślić ich średnią, a następnie dodać adnotację do zestawu zapytań o tę średnią, jak zakładam.

Odpowiedz

1

Myślę, że najlepiej jest utworzyć widok SQL z kolumną date_end - date_start, utworzyć model django w tym widoku, a następnie będzie można zapytać widok i adnotować go, jak chcesz. Zrobiłem to z modelami podobnymi do twoich i być może mógłbym wydobyć dla ciebie interesujący kod, jeśli potrzebujesz.

+0

Tak, jeśli można podać kilka przykładów kodu byłoby wspaniale, thanks –

1

Musisz utworzyć queryset metodą extra dodać różnicę dat do każdego wiersza

Następnie użyj metody aggregate obliczyć średnią dla właśnie dodanej kolumnie:

Bądź ostrożny , ta metoda jest powolna i nie będzie skalowana. Przechowywanie obliczonej wartości na typ zdarzenia to imho najlepsza opcja.

2

Sugerowałbym, że można przechowywać trwania eventu jako kolumna:

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) 

Następnie można korzystać z tej biblioteki: http://code.google.com/p/django-cube/ obliczyć średnią na kilku różnych wymiarach (rok, typ, lub inne):

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

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

Użyj kostkę tak:

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

lub można uzyskać wszystkie średnie na wszystkich latach:

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

lub rodzaj lat/event:

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

nie wiem ale to rozwiązanie wydaje się przełamywać ORM, aby obliczyć wartość, niemniej jednak uważam, że Django jeszcze tego nie obsługuje. –

18

Wystarczy aktualizacji. W Django 1.8 jest to możliwe do zrobienia:

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) 

po którym można uruchomić zapytań typu:

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

Czy nie powinno to być date_end - date_start? –

+0

@AndreBossard masz absolutną rację. dzięki – ryuusenshi

+1

Testowanie w Django 1.8, to nie działa, gdy zostanie zastosowane do funkcji agregujących (np. Event.objects.annotate (duration = duration) .aggregrate (Avg ('duration'))) –