Группировка по неделям и добавление «пропущенных» недель - PullRequest
8 голосов
/ 26 февраля 2012

В моей модели 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     |

Какой лучший способ сделать это в Джанго? Общие решения Python также в порядке.

Ответы [ 3 ]

5 голосов
/ 26 февраля 2012

Django's 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
0 голосов
/ 08 декабря 2016

Поскольку мне приходится запрашивать несколько таблиц, объединяя их, я использую представление 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

после получения строк из этого представления БД, используйте способ @danihp для заполнения 0 для "дыр" недель / месяцев.

ПРИМЕЧАНИЕ: это проверено только для бэкэнда MySQL, я не уверен, что это нормально для MS SQL Server или других.

0 голосов
/ 26 февраля 2012

После поиска в django-запросе api doc я не нашел способа сделать запрос через систему django ORM. Курсор - это обходной путь, если бренд вашей базы данных 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)

Это, на мой взгляд, лучшее решение для повышения производительности.Но обратите внимание, что это не дополняет пропущенные недели.

EDITED Независимое решение для бренда базы данных с помощью 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

(Отказ от ответственности: не тестировался)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...