Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django filter events occurring today

Tags:

python

django

I'm struggling to logically represent the following in a Django filter. I have an 'event' model, and a location model, which can be represented as:

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

For a given location, I want to select all events occurring today. I've tried various strategies via a 'bookings_today' method in the EventManager, but the right filter syntax eludes me:

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

date() fails as this zeroes out the times, and time during the day is critical to the app, the same goes for min and max of the dates, and using them as bookends. In addition, there are multiple possible valid configurations:

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

Do I need to code a whole set of different options or is there a more simple and elegant method?

like image 617
jvc26 Avatar asked Jun 28 '12 13:06

jvc26


4 Answers

You'll need two distinct datetime thresholds - today_start and 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())

Anything happening today must have started before today_end and ended after today_start, so:

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. Having a DateTimeField (not a DateField) called foo_date is irritatingly misleading - consider just start and end...)

like image 171
Kristian Glass Avatar answered Oct 25 '22 10:10

Kristian Glass


None of the answers I saw is timezone aware.

Why don't you just do this instead:

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))
like image 34
Anthony Anyanwu Avatar answered Oct 25 '22 11:10

Anthony Anyanwu


You need to use a range there like this:

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
like image 7
Aidas Bendoraitis Avatar answered Oct 25 '22 12:10

Aidas Bendoraitis


timezone.localtime(timezone.now()).date() gets you the correct date.

To get events occurring today(start today):

from django.utils import timezone

class EventManager(models.Manager):
    def bookings_today(self, location_id):
        t = timezone.localtime(timezone.now())
        bookings = self.filter(location=location_id, start__year = t.year,
            start__month = t.month, start__day = t.day, )
like image 5
suhailvs Avatar answered Oct 25 '22 11:10

suhailvs