如果你只是想获取没有时间数据的日期,可以使用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 将我创建的两个字段合并为一个字段,例如将其格式化为字符串。这样做的好处是,您可以使用tuples 构造一个Counter 以方便查询(使用values_list())。
这个查询肯定会比在 Python 中进行计数更有效。但是,对于可能不那么重要的后台作业。
一个缺点是此代码不可移植;一方面,它不适用于 SQLite,您可能仍将其用于测试目的。在这种情况下,您可能会省去麻烦并立即编写 raw 查询,这将同样不可移植但更具可读性。
更新
由于添加了TruncHour,从 1.10 开始,可以使用 expressions 很好地执行此查询。以下是解决方案外观的建议:
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)]
它优雅、高效且便携。 :)