Django 按时间过滤日期时间字段,与日期无关

Posted

技术标签:

【中文标题】Django 按时间过滤日期时间字段,与日期无关【英文标题】:Django filter datetime field by time, irrespective of date 【发布时间】:2015-03-06 21:03:25 【问题描述】:

我在 Django 中有一个日期时间字段,我想根据时间对其进行过滤。我不关心具体的日期,但我想找到例如 7:30 之前的所有交易。

我知道我可以按小时和分钟过滤,例如:

Q(datetime__hour=7) & \
Q(datetime__minute=30)

但是,这会在 7:30 找到所有交易。您也无法申请 gte 或 lte。即

(Q(datetime__hour__lte=7) & \
Q(datetime__minute__lte=30)) | \
Q(datetime__hour__lt=7)

似乎唯一可能的解决方案是有许多查询,例如:

(Q(datetime__hour=7) & \
(Q(datetime__minute=30) | \
 Q(datetime__minute=29) | \
 Q(datetime__minute=28) | \
 ....
 Q(datetime__minute=2) | \
 Q(datetime__minute=1) | \
 Q(datetime__minute=0))) | \
Q(datetime__hour=6) | \
Q(datetime__hour=5) | \
Q(datetime__hour=4) | \
Q(datetime__hour=3) | \
Q(datetime__hour=2) | \
Q(datetime__hour=1) | \
Q(datetime__hour=0)

但这似乎很荒谬。

有人有什么想法吗?

【问题讨论】:

试试这个 myClass.objects.filter(condition here).order_by('-datetime') How can I filter a date of a DateTimeField in Django? 的可能重复项 XORcist - 不是重复的。该链接完全相反。它想按日期过滤,忽略时间。我想按时间过滤,忽略日期。 Gaurav - 这只会以不同的方式排列结果。这不会过滤。 为什么不能使用您的 lte 解决方案? 【参考方案1】:

想法:

使用原始 sql (mem) 缓存您的结果(例如:::pseudocode:: md5(sql_string) = sql_result)。 创建一个包含 5 个索引整数列(年、月、日、小时、分钟)的中间表。在您的主要 sql 提取之前,请检查此表以获取所需的数据(查询应该非常快)。如果什么都不存在,请进行“神奇”交易(最好不要使用 Django 的 ORM)。结果将其用于您的目的,但也将其复制到您的辅助表中。 当你厌倦了做不必要的操作时,打发一些睡眠时间并根据项目需求优化你的 sql 结构:需要什么数据、数据库写入量与数据库读取量、内部/外部连接等...

【讨论】:

【参考方案2】:

只需将日期时间字段拆分为日期和时间字段。比你只能按时过滤:

from datetime import combine

class MyModel(models.Model):
    start_date = models.DateField()
    start_time = models.TimeField()

    class Meta:
        ordering = ['start_date', 'start_time']

    def start_datetime(self):
        return combine(self.date, self.time)

我添加了 Meta.ordering 和 start_datetime 模型方法,以表明该模型可以像具有 DateTimeField 的模型一样呈现数据。

现在您可以按时过滤了:

objects = MyModel.objects.filter(start_time__lt=time(7, 30))

更新

如果您有一个已建立的项目并且许多查询都依赖于具有正常的 DateTime 字段。将日期时间拆分为日期和时间字段需要付出代价:重写查询会导致您的项目失败。有一个替代方法:只添加一个时间字段并保持日期时间字段不变。保存方法可以根据日期时间添加时间。不利的一面是您的数据库中有重复的数据。好处是它可以用最少的努力解决您的问题。

class MyModel(models.Model):
    start_datetime = models.DateTimeField()
    start_time = models.TimeField(blank=True)

    def save(self)
        self.start_time = self.start_datetime.time

所有现有查询将与以前相同,并且仅按时过滤:

objects = MyModel.objects.filter(start_time__lt=time(7, 30))

【讨论】:

可能是可能的。然而,由于这是一个已建立的项目,并且一些外部事物依赖于数据及其格式,它也可能不是......我会检查一下。不过,我会说这是迄今为止最好的解决方案。 更新:现有项目的替代方案。 谢谢大写。我认为这是最好的解决方案。【参考方案3】:

在 Django 1.7+ 中,您可以使用转换从时间戳中提取分钟和小时。看 https://docs.djangoproject.com/en/1.7/howto/custom-lookups/#a-simple-transformer-example了解详情。

【讨论】:

很遗憾,我们目前还无法迁移到 1.7。不过应该会在未来几个月内发生。

以上是关于Django 按时间过滤日期时间字段,与日期无关的主要内容,如果未能解决你的问题,请参考以下文章

Django 仅基于日期过滤日期时间

如何按 Django-filter 包中的日期字段进行过滤?

Django - 如何使用 Django Rest Framework 按日期过滤?

Django:按日期过滤日期时间忽略时间

如何使用 django F 表达式仅过滤日期时间字段的日期

Django:按计算字段过滤