Группировка дат в Django

Мой вопрос почти такой же, как этот пост, за исключением того, что я использую Python и Django вместо PHP.

Задача:

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 

И вывод:

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

Я могу вручную взломать что-то вместе, перейдя по отсортированным датам и выведя HTML в строку в моем файле представления python, но мне интересно: есть ли лучший способ использовать шаблон Django или отличную функцию Python?

Ответ 1

Вы можете решить эту проблему с помощью шаблонов tempatetags для групп и групп.

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

Ответ 2

itertools.groupby - ваш дорогой, дорогой друг:

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

Приведенный выше код печатает следующее:

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')

Ответ 3

Когда отчеты больших наборов данных itertools.group_by могут быть слишком медленными. В тех случаях я делаю postgres обрабатывать группировку:

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')

Ответ 4

Это все разумные ответы, если OP может использовать python в коде шаблона. (И в этом случае я бы предпочел решение itertools.groupby().) Но вы не можете использовать python в коде шаблона. В лучшем случае вы должны написать templatetag, который выполнил эту операцию. И уже есть templatetag, который делает это.

Чтобы выполнить группировку в Django внутри шаблона, используйте группу:

{% 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>

Пример снят с документация Django regroup. перегруппировка доступна в django 0.96, 1.0, и 1.1, по крайней мере.

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

Кроме того, есть сообщение в блоге, в котором DjangoGrrl работает именно по этому вопросу.

Ответ 5

Это было бы проще, если бы вы использовали функции форматирования даты в базе данных, чтобы отключить время (в выборе). Затем вы можете группировать форматированный столбец (используя псевдоним столбца).

После этого вы можете использовать цикл с небольшой логикой, чтобы перенести результаты на то, что вы хотите. Я еще не использовал систему шаблонов django, но вот как выглядит логика в 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

Должен быть прямой способ конвертировать это в код шаблона django.