I am trying to write a custom PostgreSQL function in Django that will coerce datetimes to a specified timezone inside of a queryset. My first pass at the db function looks like this:
from django.db.models.expressions import Func
class DateTimeInTimezone(Func):
template="%(expressions)s AT TIME ZONE %(tz_info)s"
This function works in the simple case where I pass a timezone string into the function directly like so:
MyModel.objects.filter(timefield__gte=DateTimeInTimezone(Now(), tz_info='EST'))
However it doesn't work in the more complex case, where the timezone is defined on some field on the model. Consider the following contrived example:
class User(models.Model):
time_zone = models.CharField()
class Meeting(models.Model):
users = models.ManyToManyField(User, related_name='meetings')
start_time = models.DateTimeField() # in UTC
end_time = models.DateTimeField() # in UTC
To answer the question "What users will be in a meeting at 12pm local time today?", I'd need some variation of this queryset:
noon_utc = ...
User.objects.filter(
meetings__start_time__lte=DateTimeInTimezone(noon_utc, tz_info=F('time_zone')),
meetings__end_time__gt=DateTimeInTimezone(noon_utc, tz_info=F('time_zone'))
)
As currently written, however, DateTimeInTimezone
will simply inject the string F('time_zone')
into the sql rather than resolving the field.
Is it possible to add support for F Expressions to this function? Is there some other approach that I should consider?