有没有办法通过Django ORM查询修改日期时间对象?

时间:2016-07-08 16:25:48

标签: python django python-3.x django-models django-queryset

我们有一个Django,Postgresql数据库,其中包含以下对象:

object_date = models.DateTimeField()

作为一个领域。

我们需要每天按小时计算对象,因此我们需要删除一些额外的时间数据,例如:分钟,秒和微秒。

我们可以删除python中的额外时间数据:

query = MyModel.objects.values('object_date')
data = [tweet['tweet_date'].replace(minute=0, second=0, microsecond=0) for tweet in query

这给我们留下了一个包含日期和时间的列表。

我的问题:在查询本身中有更好,更快,更清晰的方法吗?

2 个答案:

答案 0 :(得分:2)

count = len(MyModel.objects.filter(object_date__range=(beginning_of_hour, end_of_hour)))

count = MyModel.objects.filter(object_date__range=(beginning_of_hour, end_of_hour)).count()

假设我理解了您要求的内容,则返回具有特定时间范围内日期的对象数。将范围设置为从小时开始到小时结束,您将返回在该小时内创建的所有对象。可以使用Count()len(),具体取决于所需的用途。有关详细信息,请查看https://docs.djangoproject.com/en/1.9/ref/models/querysets/#count

答案 1 :(得分:1)

如果您只想获取没有时间数据的日期,可以使用extra来声明计算字段:

query = MyModel.objects
    .extra(select={
        'object_date_group': 'CAST(object_date AS DATE)',
        'object_hour_group': 'EXTRACT(HOUR FROM object_date)'
    })
    .values('object_date_group', 'object_hour_group')

尽管如此,你并没有从中获得太多收益;数据库现在向您发送更多数据。

但是,使用这些附加字段,您可以使用聚合通过添加一行来立即获取您要查找的计数:

query = MyModel.objects
    .extra(select={
        'object_date_group': 'CAST(object_date AS DATE)',
        'object_hour_group': 'EXTRACT(HOUR FROM object_date)'
    })
    .values('object_date_group', 'object_hour_group')
    .annotate(count=Count('*'))

或者,您可以使用任何有效的SQL将我将两个字段组合成一个字段,例如将其格式化为字符串。这样做的好处是,您可以使用tuple构建Counter以便于查询(使用values_list())。

这个查询肯定比在Python中进行计数更有效。但是,对于可能不那么重要的后台工作。

一个缺点是这段代码不可移植;例如,它不适用于SQLite,您可能仍在使用它来进行测试。在这种情况下,您可以省去麻烦并立即编写raw查询,这将是不可移植但更具可读性。

更新

从1.10开始,由于添加了expressions,因此可以使用TruncHour很好地执行此查询。以下是对解决方案外观的建议:

from collections import Counter
from django.db.models import Count
from django.db.models.functions import TruncHour

counts_by_group = Counter(dict(
    MyModel.objects
        .annotate(object_group=TruncHour('object_date'))
        .values_list('object_group')
        .annotate(count=Count('object_group'))
)) # query with counts_by_group[datetime.datetime(year, month, day, hour)]

优雅,高效,便携。 :)