2009-08-06 17 views
13

Mi pregunta es casi exactamente igual a this post, excepto que estoy usando Python y Django en lugar de PHP.Agrupación de fechas en Django

La tarea es tomar:

id date 
1 2009-01-01 10:15:23 
2 2009-01-01 13:21:29 
3 2009-01-02 01:03:13 
4 2009-01-03 12:20:19 
5 2009-01-03 13:01:06 

y de salida:

2009-01-01 
1 
2 
2009-01-02 
3 
2009-01-03 
4 
5 

puedo cortar manualmente algo juntos haciendo un bucle a través de las fechas ordenados y salida HTML en una cadena en mi archivo de vista pitón , pero me pregunto: ¿hay una forma mejor de usar una plantilla de Django o una característica de Python ingeniosa?

Respuesta

30

Puede resolver esto con el reagrupamiento y fecha templatetags.

{% regroup object_list by start_date|date:"Y-m-d" as objects_by_day %} 
{% for d in objects_by_day %} 
### DO SOMETHING HERE 
{% endfor %} 
+0

Estuve todo el camino hasta allí, pero no me di cuenta de que podía mezclar el filtro de fecha. Muchas gracias por esto! Exactamente lo que estaba buscando. – saturdayplace

+0

Dios mío, ¿cómo no sé sobre esto? –

+0

es más rápido utilizar start_date.date si necesita 'la porción de fecha' –

2

Esto sería más fácil si usaba las funciones de formato de fechas de su base de datos para quitar los tiempos (en la selección). A continuación, puede agrupar por la columna formateada (utilizando un alias de columna).

Después de eso, puede usar un bucle con un poco de lógica para transponer los resultados a lo que desea. No he utilizado el sistema de plantillas de Django todavía, pero esto es lo que la lógica se vería en Python:

>>> rows = [(1,'2009-01-01'), (2,'2009-01-01'), (3, '2009-02-02'), \ 
(4, '2009-02-02'), (5, '2009-02-02')] 
>>> topdate = None 
>>> for r in rows: 
...  if topdate <> r[1]: 
...    topdate = r[1] 
...    print r[1] 
...  print r[0] 
... 
2009-01-01 
1 
2 
2009-02-02 
3 
4 
5 

Debe haber una manera recta hacia adelante para convertir a este django código de la plantilla.

+0

Puedo agrupar los datos, pero ¿cómo sería la "pequeña lógica" dentro del sistema de plantillas? – ine

+0

Agregué un ejemplo. –

+0

No estoy seguro de que pueda hacer esto en las plantillas de Django. Incluso si pudieras, no querrías. Es mejor hacerlo en: (1) el código de vista o (2) una etiqueta de plantilla donde puede usar python real. – hughdbrown

15

itertools.groupby es su querida, querido amigo:

import itertools 

dates = [ 
    (1,'2009-01-01 10:15:23'), 
    (2,'2009-01-01 13:21:29'), 
    (3,'2009-01-02 01:03:13'), 
    (4,'2009-01-03 12:20:19'), 
    (5,'2009-01-03 13:01:06'), 
] 

for key,group in itertools.groupby(dates, key=lambda x: x[1][:11]): 
    print key 
    for element in group: 
     print ' ', element 

El código anterior imprime los siguientes:

2009-01-01 
    (1, '2009-01-01 10:15:23') 
    (2, '2009-01-01 13:21:29') 
2009-01-02 
    (3, '2009-01-02 01:03:13') 
2009-01-03 
    (4, '2009-01-03 12:20:19') 
    (5, '2009-01-03 13:01:06') 
+0

¡Excelente! itertools.groupby es justo lo que estaba buscando. – ine

+0

Si va a hacerlo en la vista, que desea algo como esto: "def sidebar_date_list(): de itertools importar GroupBy de datos = [datetime.date (post.created_at.year, post.created_at.month , 1) para publicar en Post.objects.filter (publish = 1) .order_by ('- created_at')] return {'months': [k for k, _ in groupby (data)]} Observe que la SQL tiene que ser ordenado por groupby() para usar. " Levantado desde aquí: http://www.djangrrl.com/view/using-python-str-datetime-lists-and-sets-to-group-dates/ – hughdbrown

+0

O así, si quieres agrupar por días: " def sidebar_date_list(): \t desde el grupo de importación de itertools por \t data = [date.date.date (post.created_at.year, post.created_at.month, post.created_at.day) para publicar en Post.objects.filter (publish = 1) .order_by ('- created_at')] \t return {'days': [k for k, _ in groupby (data)]} " – hughdbrown

8

Estas son todas las respuestas razonables si el OP podría usar pitón en el código de la plantilla. (Y en esa cuenta, yo preferiría la solución itertools.groupby()). Pero no puedes usar Python en el código de la plantilla. En el mejor de los casos, debe escribir una plantilla que realiza esta operación. Y ya hay una plantilla que hace esto.

para hacer la agrupación en Django dentro de la plantilla, utilice reagrupamiento:

{% regroup people by gender as gender_list %} 

<ul> 
{% for gender in gender_list %} 
    <li>{{ gender.grouper }} 
    <ul> 
     {% for item in gender.list %} 
     <li>{{ item.first_name }} {{ item.last_name }}</li> 
     {% endfor %} 
    </ul> 
    </li> 
{% endfor %} 
</ul> 

Ejemplo levantado de Django regroup documentation. reagrupar está disponible en django 0.96, 1.0 y 1.1, al menos.

Si me hiciste una idea de lo que se transfiere a la plantilla, podría hackear un ejemplo que use tus datos.

Además, hay un blog post en el que DjangoGrrl resuelve exactamente esta pregunta.

+0

Los lenguajes de plantilla tienden a proporcionar suficientes construcciones del mismo lenguaje que puede convertir fácilmente entre los dos (comparten el mismo código de bytes de destino). –

+0

No sea grosero, pero ¿programa en Django? A efectos prácticos, solo hay comparaciones rudimentarias y operaciones de asignación. Echa un vistazo a lo que está disponible sin usar templatetags: http://docs.djangoproject.com/en/dev/topics/templates/ – hughdbrown

+0

Desafortunadamente, estoy usando 0.96 pero este es un gran recurso para aquellos con 1.0 o más. – ine

9

Al realizar informes en conjuntos de datos más grandes itertools.group_by puede ser demasiado lento. En esos casos hago postgres manejar la agrupación:

truncate_date = connection.ops.date_trunc_sql('day','timestamp') 
qs = qs.extra({'date':truncate_date}) 
return qs.values('date').annotate(Sum('amount')).order_by('date')