Django按小时分组

5
我在Django中有以下模型。
class StoreVideoEventSummary(models.Model):
    Customer = models.ForeignKey(GlobalCustomerDirectory, null=True, db_column='CustomerID', blank=True, db_index=True)
    Store = models.ForeignKey(Store, null=True, db_column='StoreID', blank=True, related_name="VideoEventSummary")
    Timestamp = models.DateTimeField(null=True, blank=True, db_index=True)
    PeopleCount = models.IntegerField(null=True, blank=True)

我希望知道每小时进入商店的人数。 为了达到这个目的,我试图按时间戳的小时分组,并求出PeopleCount列的总和。
store_count_events = StoreVideoEventSummary.objects.filter(Timestamp__range=(start_time, end_time),
                                                       Customer__id=customer_id,
                                                       Store__StoreName=store)\
        .order_by("Timestamp")\
        .extra({
            "hour": "date_part(\'hour\', \"Timestamp\")"
        }).annotate(TotalPeople=Sum("PeopleCount"))

看起来这个查询并没有按小时分组结果,它仅仅是向查询集合中的每一行添加了一个新列TotalPeople,并将其值设置为PeopleCount的值。


我感觉有些东西不对劲,"StartTime" 是从哪里来的? "hour": "date_part(\'hour\', \"StartTime\")" - nivix zixer
抱歉,应该是“时间戳”。 - CadentOrange
3个回答

12

只需将其分为两个步骤

import itertools
from datetime import datetime


# ...

def date_hour(timestamp):
    return datetime.fromtimestamp(timestamp).strftime("%x %H")


objs = StoreVideoEventSummary.objects.filter(
    Timestamp__range=(start_time, end_time),
    Customer__id=customer_id,
    Store__StoreName=store
).order_by("Timestamp")

groups = itertools.groupby(objs, lambda x: date_hour(x.Timestamp))

# since groups is an iterator and not a list you have not yet traversed the list
for group, matches in groups:  # now you are traversing the list ...
    print(group, "TTL:", sum(1 for _ in matches))

这使您可以按照几个不同的标准进行分组

如果您只想按小时而不考虑日期,只需更改 date_hour

def date_hour(timestamp):
   return datetime.fromtimestamp(timestamp).strftime("%H")
如果您想按星期几分组,只需使用:

def date_day_of_week(timestamp):
   return datetime.fromtimestamp(timestamp).strftime("%w %H")

itertools.groupby 中的 lambda 表达式更新为使用 date_day_of_week


完全忘了itertools。 在Python中进行分组是有效的,如果其他方法都失败了,我认为这是我要采用的方法。 如果可能的话,在数据库中完成它会很好,因为我想象那会更快。 再说,我的数据集并不是那么大(著名的最后一句话!)。 - CadentOrange
你会惊讶的...在数据库中可能并不更快 :P - Joran Beasley
这种方法似乎很有效。我们还没有遇到任何问题,可能是因为我们的数据集很小。 - CadentOrange
由于您只是进行一次迭代,所以时间复杂度应为O(N)……这应该相当容易处理。 - Joran Beasley
@JoranBeasley 最优雅的解决方案加一。它对我有用,但是我想知道 sum(1 for _ in matches) 语法是什么意思?我想研究一下,但不知道该搜索什么。 - Vlad T.

1

start_time和end_time是什么,它们在哪里定义的? - Rahul Sharma
hour(TimeStamp)中的hour是什么意思? - Gilbish Kosma

1

基于您的原始代码,您能否尝试:

store_count_events = StoreVideoEventSummary.objects.filter(Timestamp__range=(start_time, end_time), Customer__id=customer_id, Store__StoreName=store)\
    .extra({
        "hour": "date_part(\'hour\', \"Timestamp\")"
    })\
    .values("hour")\
    .group_by("hour")\
    .annotate(TotalPeople=Sum("PeopleCount"))

似乎不能正常工作。它与之前的相似,唯一的区别似乎是现在每行只有2个字段hourTotalPeople,而不是整行数据。 - CadentOrange
“QuerySet”对象没有“group_by”属性。 - mrash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接