django - 当时区信息存储在数据库中时,Django 按一天中的小时过滤
问题描述
具有以下模型结构:
class Place(models.Model):
...
timezone = TimeZoneField() # Defined in a package called django-timezone-utils
...
class Session(models.Model):
...
place = model.ForeignKey(Place, ...)
created = models.DateTimeField(auto_now_add=True) # Saved in utc
...
我想获取在一天中的第 10 个小时内创建的所有会话。对此的基本方法是:
Session.objects.filter(created__hour=10)
但是,正如预期的那样,结果将按 UTC 时间过滤。如何获取在一天中的第 10 个小时内创建的 Sessions 对象,在它们连接到的地方的时区中?请注意,可能会在具有不同时区的不同地点进行会话,但我想获取在当地时区的一天中的第 10 个小时内创建的会话。
使用本地时区中的创建时间注释每个结果,然后过滤该注释值可能会起作用,但我不知道如何构建该注释
解决方案
我通过定义将日期时间字段转换为时区的自定义数据库函数来完成我想要的,该时区也在相关列中定义。现在仅适用于 postgres(使用“在时区”表达式),但可以更新以使用其他数据库引擎以及使用它们的时区转换功能。
从 django.db.models 导入函数,日期时间字段
class ConvertToTimezone(Func):
"""
Custom SQL expression to convert time to timezone stored in database column
"""
output_field = DateTimeField()
def __init__(self, datetime_field, timezone_field, **extra):
expressions = datetime_field, timezone_field
super(ConvertToTimezone, self).__init__(*expressions, **extra)
def as_sql(self, compiler, connection, fn=None, template=None, arg_joiner=None, **extra_context):
params = []
sql_parts = []
for arg in self.source_expressions:
arg_sql, arg_params = compiler.compile(arg)
sql_parts.append(arg_sql)
params.extend(arg_params)
return "%s AT TIME ZONE %s" % tuple(sql_parts), params
这就是我使用它的方式:
Session.objects.annotate(created_local=ConvertToTimezone('created', 'place__timezone')).filter(created_local__hour=10)
我对 Django 数据库函数和数据库表达式的工作方式没有深入的了解,因此欢迎(并且愿意听到)对解决方案的任何反馈/改进
推荐阅读
- amazon-web-services - Cloudfront CDN 尊重客户端缓存控制:无存储(无缓存)请求标头?
- node.js - 我可以通过在其中导入 Json 文件来自动制作 RapidPro 流程吗?如何?
- php - 自定义/修剪/替换 Wordpress 单个类别标题
- python - 'For' 循环:创建一个新列,其中考虑了来自多个 csv 文件的新数据
- c# - “var”调试显示不存在的“System.Configuration.KeyValueInternalCollection”,这是怎么回事?
- migration - magento 迁移 m1 到 m2
- r - 解析一组值的第一个实例
- javascript - 如何对具有多个条件的 MongoDB 集合中所有文档的键值求和
- python - spacy 如何将模式添加到现有的实体标尺?
- wordpress - 尝试在 woocommerce_email_order_details 操作中访问 functions.php 中的 ACF 值