加速django嵌套循环时间序列

Dav*_*vid 5 python django optimization performance datetime

我的工作称为OpenREM(一个基于Django的开源项目http://demo.openrem.org/openrem/,http://openrem.org).

为了计算其中一个图表的数据,我正在进行一系列查询,以获得一周中每天24小时内每个项目的数量.此数据用于在演示站点的CT页面上绘制每个工作日的研究饼图,并向下钻取到当天每小时的研究:

studiesPerHourInWeekdays = [[0 for x in range(24)] for x in range(7)]
for day in range(7):
    studyTimesOnThisWeekday = f.qs.filter(study_date__week_day=day+1).values('study_time')
    if studyTimesOnThisWeekday:
        for hour in range(24):
            try:
                studiesPerHourInWeekdays[day][hour] = studyTimesOnThisWeekday.filter(study_time__gte = str(hour)+':00').filter(study_time__lte = str(hour)+':59').values('study_time').count()
            except:
                studiesPerHourInWeekdays[day][hour] = 0
Run Code Online (Sandbox Code Playgroud)

这需要一段时间才能在生产系统上运行.我认为第二个FOR循环可以通过使用qsstats-magic time_series删除,聚合时间超过几小时.遗憾的是,数据库中没有合适的日期时间对象可以用于此目的.

有谁知道如何将"study_date"datetime.date对象和"study_time"datetime.time对象组合成一个datetime.datetime对象,以便能够按小时运行qsstats-magic time_series?

谢谢,

大卫

R P*_*gna 1

如果您可以(尽管考虑到您的情况,您似乎无法做到),最好更改数据库架构以反映您正在进行的查询类型。包含此信息的日期时间字段、设置的某种类型的外键等。

不过,您可能已经知道这一点,因此您问题的实际答案是您希望通过extra() 调用来使用底层数据库工具来发挥您的优势。如果你使用 postgres,也许是这样的*:

date_hour_set = f.qs.extra(
    select={
        'date_hour': "study_date + interval '1h' * date_part('hour', study_time)",
        'date_hour_count': "count(study_date + interval '1h' * date_part('hour', study_time))"
    }).values('date_hour', 'date_hour_count').distinct()
Run Code Online (Sandbox Code Playgroud)

这将为您提供日期时间(仅限小时)及其相关出现次数的查询集。由于Django 滞后的 TimeField 支持,手写 SQL 将为您提供目前最简单的选择,并且也可能是性能最高的。

*注意我不定期编写 SQL 并且很懒,所以有更干净的方法来解决这个问题。

如果您确实需要数据库可移植并且仍然无法编辑架构,您可以将 Django 聚合的功能堆叠在一起,这些功能可能有点复杂:

from django.db.models import Value, Count, ExpressionWrapper, CharField
from django.db.models.functions import Substr, Concat

hour_counts = f.qs.annotate(hour=Concat(Substr('study_time', 1, 2), Value(':00:00')))
date_hour_pairs = hour_counts.annotate(
        date_hour=ExpressionWrapper(Concat('study_date', 'hour'),
        output_field=CharField())).values('study_date', 'hour', 'date_hour')
date_hour_counts = date_hour_pairs.annotate(count=Count('date_hour')).distinct()
Run Code Online (Sandbox Code Playgroud)

它应该为您提供一组字典,其中包含“hour”的 datetime.time 对象、您开始的“study_date”的 datetime.date、“date_hour”下日期和时间的连接字符串版本,然后是所有重要的内容(日期、小时)在“计数”下计数。