【问题标题】:Django filter datetime field by time, irrespective of dateDjango 按时间过滤日期时间字段,与日期无关
【发布时间】: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')
  • XORcist - 不是重复的。该链接完全相反。它想按日期过滤,忽略时间。我想按时间过滤,忽略日期。
  • Gaurav - 这只会以不同的方式排列结果。这不会过滤。
  • 为什么不能使用您的 lte 解决方案?

标签: python django datetime


【解决方案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。不过应该会在未来几个月内发生。
    猜你喜欢
    • 2022-08-22
    • 2018-01-25
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 2023-03-23
    • 2021-07-03
    • 2014-03-22
    • 1970-01-01
    相关资源
    最近更新 更多