2009-08-06 50 views
13

我的問題幾乎和this post一樣,除了我使用Python和Django而不是PHP。在Django中分組日期

的任務是採取:

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功能?

回答

30

您可以通過重組日期 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

我是那裏的大部分,但沒有意識到你可以混合使用日期過濾器。非常感謝!正是我在找什麼。 – saturdayplace 2010-04-16 22:26:29

+0

好神,怎麼沒我知道這個 – 2012-01-26 10:36:33

+0

它的速度更快,如果你需要「日期部分」 – 2014-01-06 18:47:56

2

如果您使用數據庫的日期格式功能剝離時間(在選擇中),這將會更容易。然後您可以按格式化列進行分組(使用列別名)。

之後,您可以使用一個邏輯小的循環來將結果轉換爲您想要的結果。我沒有使用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的模板代碼直接的方式。

+0

我可以將數據分組,但模板系統內部的「小邏輯」是什麼樣子? – ine 2009-08-06 04:18:07

+0

我添加了一個例子。 – 2009-08-06 05:06:18

+0

我不相信你可以在Django模板中做到這一點。即使你可以,你也不想。最好這樣做: (1)視圖代碼或(2)可以使用真正的Python的模板標籤。 – hughdbrown 2009-08-06 17:14:29

15

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

非常好! itertools.groupby就是我正在尋找的。 – ine 2009-08-06 18:08:25

+0

如果您打算在視圖中執行此操作,您需要如下所示: 「ite sidebar_date_list(): from itertools import group by data = [datetime.date(post.created_at.year,post.created_at.month ,1)Post.objects.filter(publish = 1).order_by(' - created_at')] return {'months':[k for k,_ in groupby(data)]} 請注意, SQL必須被排序以供groupby()使用。「從這裏解除: http://www.djangrrl.com/view/using-python-str-datetime-lists-and-sets-to-group-dates/ – hughdbrown 2009-08-06 18:17:42

+0

或者像這樣,如果你想按天分組:「 def sidebar_date_list(): \t from itertools import groupby \t data = [datetime.date(post.created_at.year,post.created_at.month,post.created_at.day)for post in Post.objects.filter(publish = 1) ).order_by( ' - created_at')] \t回{ '天':[K爲K,_在GROUPBY(數據)]}」 – hughdbrown 2009-08-06 18:19:47

8

這些都是合理的答案,如果OP可在模板代碼使用Python。 (就此而言,我贊成itertools.groupby()解決方案。)但是,您不能在模板代碼中使用python。在最好的情況下,你會寫一個執行這個操作的模板標籤。而且已經有一個模板標籤可以做到這一點。

做分組在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 documentation解除。 regroup至少可在django 0.961.01.1中找到。

如果你給了我一個關於傳遞給模板的信息,我可以用一個使用你的數據的例子來破解它。

另外,還有一個blog post其中DjangoGrrl完全通過這個問題。

+0

模板語言傾向於提供足夠的相同語言結構,您可以輕鬆地在兩者之間進行轉換(它們共享相同的目標字節碼)。 – 2009-08-06 17:40:40

+0

不要粗魯,但是你在Django中編程嗎?實際上,只有基本的比較和分配操作。看看什麼是可用的,而無需使用templatetags: http://docs.djangoproject.com/en/dev/topics/templates/ – hughdbrown 2009-08-06 18:03:51

+0

不幸的是,我使用的是0.96,但是這是爲那些對1.0或更高的很好的資源! – ine 2009-08-06 18:06:33

9

在做大型數據集報告時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')