2012-02-26 12 views
7

W moim modelu Django, mam bardzo prosty model, który reprezentuje pojedynczy wystąpienie zdarzenia (takiego jak serwer występujące alert):Grupowanie przez tydzień, a wyściółka out „brakuje” tydzień

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

Moim celem końcowym jest wygenerowanie tabeli lub wykresu pokazującego, ile razy zdarzyło się wydarzenie w ciągu ostatnich tygodni: n.

Więc moje pytanie składa się z dwóch części:

  • Jak mogę group_by tydzień pola time?
  • W jaki sposób mogę "wyplątać" wynik tego group_by, aby dodać wartość zerową dla brakujących tygodni?

Na przykład, dla drugiej strony, chciałbym przekształcić wynik takiego:

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

Jaki jest najlepszy sposób, aby to zrobić w Django? Ogólne rozwiązania Pythona są również w porządku.

Odpowiedz

4

Django DateField jak datetime nie obsługuje atrybut tygodniu. Aby sprowadzić wszystko w jednym zapytaniu trzeba zrobić:

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

Po wykopaniu django zapytania api doc, nie znalazłem sposobu na zrobienie zapytania przez system ORM django. Cursor jest obejście tego problemu, jeśli Twoja marka jest baza danych 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) 

To jest, moim zdaniem, najlepszym rozwiązaniem wydajność. Ale zauważ, że to nie powoduje braku tygodni.

EDITED Indepedent rozwiązania marki w bazie za pośrednictwem Python (mniejszej wydajności)

Jeśli szukasz marki bazie kodu niepodległość to należy podjąć dat z dnia na dzień i agregować go za pomocą Pythona. Jeśli jest to Twój kod przypadku wygląda następująco:

#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 

(Uwaga: nie testowane)

0

Ponieważ mam do kwerendy wielu tabel, których autorem jest dołączyć do nich, używam widok db rozwiązać te wymagania.

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

a model jako:

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 

po uzyskać wierszy z tym poglądem db użyć drogę przez @danihp do wyściółki 0 dla "dziura" tygodni/miesięcy.

UWAGA: jest to testowane tylko na backend MySQL, nie jestem pewien, czy jest to poprawne dla MS SQL Server lub innego.

Powiązane problemy