chu*_*gon 2 django django-orm django-queryset django-postgresql django-1.10
我正在尝试在 Django 中编写一个自定义 PostgreSQL 函数,它将强制日期时间为查询集中指定的时区。我对 db 函数的第一次调用如下所示:
from django.db.models.expressions import Func
class DateTimeInTimezone(Func):
template="%(expressions)s AT TIME ZONE %(tz_info)s"
Run Code Online (Sandbox Code Playgroud)
该函数适用于简单的情况,我直接将时区字符串传递到函数中,如下所示:
MyModel.objects.filter(timefield__gte=DateTimeInTimezone(Now(), tz_info='EST'))
Run Code Online (Sandbox Code Playgroud)
但是,它不适用于更复杂的情况,即时区是在模型的某些字段上定义的。考虑以下人为的示例:
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
Run Code Online (Sandbox Code Playgroud)
要回答“今天当地时间中午 12 点哪些用户将参加会议?”这一问题,我需要此查询集的一些变体:
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'))
)
Run Code Online (Sandbox Code Playgroud)
然而,按照目前的编写,DateTimeInTimezone将只是将字符串注入F('time_zone')到 sql 中,而不是解析该字段。
是否可以向此函数添加对F 表达式的支持?我还应该考虑其他方法吗?
使用参数可以实现一个简单的解决方案arg_joiner:
class DateTimeInTimezone(Func):
function = ''
arg_joiner = ' AT TIME ZONE '
def __init__(self, timestamp, tz_info):
super(DateTimeInTimezone, self).__init__(timestamp, tz_info)
Run Code Online (Sandbox Code Playgroud)
该方法__init__仅用于参数名称清晰、可读性强的目的。那么arity参数是否由 声明并不重要__init__。
如果可读性不重要,则oneliner函数对于快速开发很有用:
...filter(
meetings__start_time__lte=Func(noon_utc, tz_info=F('time_zone'), arg_joiner=' AT TIME ZONE ', function=''),
)
Run Code Online (Sandbox Code Playgroud)
已验证:
>>> qs = User.objects.filter(...)
>>> print(str(qs.query))
SELECT ... WHERE ("app_meeting"."start_time" <= ((2017-10-03 08:18:12.663640 AT TIME ZONE "app_user"."time_zone")) AND ...)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
961 次 |
| 最近记录: |