2012-02-26 8 views
7

En mi modelo de Django, tengo un modelo muy simple que representa una única ocurrencia de un evento (como ocurre una alerta de servidor):Agrupación por semana, y el relleno hacia fuera 'perdido' semanas

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

Mi objetivo final es generar una tabla o gráfico que muestre cuántas veces ocurrió un evento en el pasado n semanas.

Así que mi pregunta tiene dos partes:

  • Como puedo group_by la semana del campo time?
  • ¿Cómo puedo "rellenar" el resultado de este group_by para agregar un valor cero para las semanas que faltan?

Por ejemplo, para la segunda parte, me gustaría transformar un resultado como este:

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

Cuál es la mejor manera de hacer esto en Django? Las soluciones generales de Python también están bien.

Respuesta

4

Django de DateField, así como datetime no admite semana atributo. Para traer todo de una consulta que tiene que hacer:

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

Después de excavar django query api doc, no he encontrado una manera de realizar consultas a través del sistema ORM django. Cursor es una solución temporal, si su marca es la base de datos 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) 

Ésta es, en mi opinión, la mejor solución de rendimiento. Pero fíjate que esto no dura semanas.

editado solución de base de datos de la marca a través de Indepedent pitón (menos de rendimiento)

Si usted está buscando para el código independece marca de base de datos, entonces debería tener fechas día a día y agregarla a través de pitón. Si este es su código de caja pueden las miradas como:

#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 

(Negación: no probado)

0

Desde que tengo que consultar varias tablas de unirse a ellos, estoy usando vista db para resolver estos requisitos.

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

y el modelo como:

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 

después de obtener los registros de esta vista db, utilice el camino por el que el relleno @danihp 0 para "agujero" de las semanas/meses.

NOTA: esto solo se ha probado para el back-end de MySQL, no estoy seguro si está bien para MS SQL Server u otro.

Cuestiones relacionadas