2012-06-28 13 views
12

Mam walkę logicznie reprezentować następujące w filtrze Django. Mam modelu „zdarzenie”, a model lokalizacji, które można przedstawić jako:Django filtr zdarzeń występujących dzisiaj

class Location(models.Model): 
    name = models.CharField(max_length=255) 

class Event(models.Model): 
    start_date = models.DateTimeField() 
    end_date = models.DateTimeField() 
    location = models.ForeignKeyField(Location) 

    objects = EventManager() 

dla danej lokalizacji, chcę, aby zaznaczyć wszystkie zdarzenia zachodzące dzisiaj. Próbowałem różnych strategii poprzez „bookings_today” metody w EventManager, ale prawo składnia filtr wymyka mi:

class EventManager(models.Manager): 
    def bookings_today(self, location_id): 
     bookings = self.filter(location=location_id, start=?, end=?) 

date() nie powiedzie się, jak to zeruje się czasy, a czas w ciągu dnia jest krytyczna aplikacja, to samo dotyczy min. i maks. terminów, i używanie ich jako bookends. Ponadto, istnieje wiele możliwych ważne konfiguracje:

start_date < today, end_date during today 
start_date during today, end_date during today 
start_date during today, end_date after today 

Czy muszę zakodować cały zestaw różnych opcji czy jest tam bardziej prosty i elegancki sposób?

+1

spojrzeć na zakres dla operatora BETWEEN SQL patrz również tę odpowiedź przez @danielroseman: http://stackoverflow.com/questions/3963201/ how-do-you-select-between-two-dates-with-django –

Odpowiedz

19

Musisz dwie odrębne datetime progi - today_start i today_end:

from datetime import datetime, timedelta, time 

today = datetime.now().date() 
tomorrow = today + timedelta(1) 
today_start = datetime.combine(today, time()) 
today_end = datetime.combine(tomorrow, time()) 

Wszystko dzieje się dzisiaj musi zaczęli przedtoday_endi zakończył potoday_start, więc:

class EventManager(models.Manager): 
    def bookings_today(self, location_id): 
     # Construction of today_end/today_start as above, omitted for brevity 
     return self.filter(location=location_id, start__lte=today_end, end__gte=today_start) 

(P.S. Posiadanie DateTimeField (nie DateField) nazywa foo_date jest irytująco mylący - rozważyć tylko start i end ...)

+0

Aha - genialny! Dzięki. – jvc26

+1

'datetime.now()' proszę – lajarre

1

Co powiesz na to: pub_date__gte=datetime(2005, 1, 1)? Użyj _gte i __lte, aby ograniczyć początek i koniec w ciągu jednego dnia za pomocą metody łączenia.

Może coś w stylu: self.filter(start__gte=datetime(2005, 1, 1)).filter(end__lte=datetime(2005, 1, 1)). lte oznacza mniej lub równiej niż, gte oznacza większą lub równą niż.

Znajduję to w django doc.

5

Trzeba użyć szeregu tam tak:

class EventManager(models.Manager): 
    def bookings_today(self, location_id): 
     from datetime import datetime 
     now = datetime.now() 
     bookings = self.filter(location=location_id, start__lte=now, end__gte=now) 
     return bookings 
+0

Co się stanie, jeśli początek i koniec wydarzenia przypadnie w dniu dzisiejszym? to by tego nie odebrało - może to być moment * headdesk *, ale czy umieszczenie end__gte = dzisiaj i start__lte = dzisiaj rozwiąże to? – jvc26

+0

Tak, masz rację. end__gte = dziś i start__lte = dziś powinny być użyte. –

+0

W porządku, to tak naprawdę nie działa, ponieważ data rozpoczęcia może spaść przed rozpoczęciem dnia dzisiejszego lub po nim, a data.today() nie wydaje się siatkować z obiektami datetime pod względem równości podczas wyboru. – jvc26

0

myślę wyklucza to twój przyjaciel tutaj!

today = datetime.date.today() 
tomorrow = today + datetime.timedelta(days = 1) 
self.filter(location = location_id).exclude(end_date__lt = today).exclude(start_date__gte = tomorrow) 
1

żadna z odpowiedzi widziałem jest świadome stref czasowych.

Dlaczego nie można po prostu to zrobić w zamian:

from django.utils import timezone 

class EventManager(models.Manager): 
    def bookings_today(self, location_id): 
     bookings = self.filter(location=location_id, start__gte=timezone.now().replace(hour=0, minute=0, second=0), end__lte=timezone.now().replace(hour=23, minute=59, second=59))