Django filter events occurring today
Question:
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?
Answers:
How about this: pub_date__gte=datetime(2005, 1, 1)
? Use _gte
and __lte
to limit start and end within one day using chaining method.
Maybe something like self.filter(start__gte=datetime(2005, 1, 1)).filter(end__lte=datetime(2005, 1, 1))
. lte
stands for less or equal than, gte
stands for greater or equal than.
I find it in django doc.
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
I think exclude is your friend here!
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 )
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
…)
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))
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, )
i have a suggestion
class Car:
name = models.CharField()
launched_date = models.DateTimeField()
it is very difficult to filter datetime field by todays date .
even if you take timezone.now() – you will not get correct output.
becuase timezone.now() has time also.
datetime field has time along with it , so even if you are giving correct date the time will not be matching.
so
it is better to use datefield for filtering based on date
class Car:
name = models.CharField()
launched_date = models.DateField()
answer for the question :-
from django.utils.timezone import datetime
today = datetime.today()
events_for_today = Event.objects.filter(start_date__year=today.year,
start_date__month=today.month,
start_date__day=today.day)
because it is a DateTimeField use start_date__date
today = datetime.now().date()
leave = Event.objects.filter(start_date__date=today)
As it is a DateTimeField
use start_date__date
and perform an OR (|)
query
from django.db.models import Q
from django.utils import timezone
today = timezone.now().date()
qs = Event.objects.filter(
Q(start_date__date=today) |
Q(end_date__date=today)
)
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?
How about this: pub_date__gte=datetime(2005, 1, 1)
? Use _gte
and __lte
to limit start and end within one day using chaining method.
Maybe something like self.filter(start__gte=datetime(2005, 1, 1)).filter(end__lte=datetime(2005, 1, 1))
. lte
stands for less or equal than, gte
stands for greater or equal than.
I find it in django doc.
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
I think exclude is your friend here!
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 )
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
…)
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))
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, )
i have a suggestion
class Car:
name = models.CharField()
launched_date = models.DateTimeField()
it is very difficult to filter datetime field by todays date .
even if you take timezone.now() – you will not get correct output.
becuase timezone.now() has time also.
datetime field has time along with it , so even if you are giving correct date the time will not be matching.
so
it is better to use datefield for filtering based on date
class Car:
name = models.CharField()
launched_date = models.DateField()
answer for the question :-
from django.utils.timezone import datetime
today = datetime.today()
events_for_today = Event.objects.filter(start_date__year=today.year,
start_date__month=today.month,
start_date__day=today.day)
because it is a DateTimeField use start_date__date
today = datetime.now().date()
leave = Event.objects.filter(start_date__date=today)
As it is a DateTimeField
use start_date__date
and perform an OR (|)
query
from django.db.models import Q
from django.utils import timezone
today = timezone.now().date()
qs = Event.objects.filter(
Q(start_date__date=today) |
Q(end_date__date=today)
)