按周分组,填补“缺失”周数

时间:2012-02-26 10:32:26

标签: python django date graph

在我的Django模型中,我有一个非常简单的模型,表示一次事件发生(例如发生服务器警报):

class EventOccurrence:
    event = models.ForeignKey(Event)
    time = models.DateTimeField()

我的最终目标是生成一个表格或图表,显示过去 n 周内事件发生的次数。

所以我的问题有两部分:

  • 我如何group_by time字段的那一周?
  • 我如何“填充”此group_by的结果,为任何遗失的周数添加零值?

例如,对于第二部分,我想像这样转换结果:

| week | count |                   | week | count |
| 2    | 3     |                   | 2    | 3     |
| 3    | 5     |   —— becomes —>   | 3    | 5     |
| 5    | 1     |                   | 4    | 0     |
                                   | 5    | 1     |

在Django中执行此操作的最佳方法是什么?一般的Python解决方案也没关系。

3 个答案:

答案 0 :(得分:5)

Django的DateField以及datetime不支持周属性。要在一个查询中获取所有内容,您需要执行以下操作:

from django.db import connection

cursor = connection.cursor()
cursor.execute(" SELECT WEEK(`time`) AS 'week', COUNT(*) AS 'count' FROM %s GROUP BY WEEK(`time`) ORDER BY WEEK(`time`)" % EventOccurrence._meta.db_table, [])

data = []
results = cursor.fetchall()
for i, row in enumerate(results[:-1]):
    data.append(row)

    week = row[0] + 1
    next_week = results[i+1][0]
    while week < next_week:
        data.append( (week, 0) )
        week += 1
data.append( results[-1] )

print data

答案 1 :(得分:0)

在挖掘django查询api文档后,我没有找到通过django ORM系统进行查询的方法。 Cursor是一种解决方法,如果您的数据库品牌是MySQL:

from django.db import connection, transaction
cursor = connection.cursor()

cursor.execute("""
   select 
      week(time) as `week`, 
      count(*) as `count` 
   from EventOccurrence 
   group by week(time)
   order by 1;""")

myData = dictfetchall(cursor)

在我看来,这是最佳性能解决方案。但请注意,这不会缺少数周。

已编辑通过python(性能较低)的独立数据库品牌解决方案

如果您正在寻找数据库品牌独立代码,那么您应该每天采用日期并通过python进行聚合。如果这是您的情况,代码可能如下所示:

#get all weeks:
import datetime
weeks = set()
d7 = datetime.timedelta( days = 7)
iterDay = datetime.date(2012,1,1)
while iterDay <= datetime.now():
    weeks.add( iterDay.isocalendar()[1] )
    iterDay += d7

#get all events
allEvents = EventOccurrence.objects.value_list( 'time', flat=True )

#aggregate event by week
result = dict()
for w in weeks:
    result.setdefault( w ,0)

for e in allEvents:
    result[ e.isocalendar()[1] ] += 1

(免责声明:未经测试)

答案 2 :(得分:0)

由于我必须通过加入来查询多个表,因此我使用db视图来解决这些需求。

CREATE VIEW my_view
  AS
  SELECT
    *, // <-- other fields goes here
    YEAR(time_field) as year,
    WEEK(time_field) as week
  FROM my_table;

和模型:

from django.db import models

class MyView(models.Model):
    # other fields goes here
    year = models.IntegerField()
    week = models.IntegerField()

    class Meta:
        managed = False
        db_table = 'my_view'

    def query():
        rows = MyView.objects.filter(week__range=[2, 5])
        # to handle the rows

从此db视图中获取行后,使用@danihp的方式为&#34; hole&#34;填充0周/月。

注意:这仅针对MySQL后端进行测试,我不确定它是否适用于MS SQL Server或其他。