2009-08-06 13 views
13

La mia domanda è quasi identica a this post, tranne che sto usando Python e Django invece di PHP.Date di raggruppamento in Django

Il compito è quello di prendere:

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 

E uscita:

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

posso incidere manualmente qualcosa insieme da scorrendo le date ordinate e l'output HTML in una stringa nel mio file vista python , ma mi chiedo: c'è un modo migliore di usare un template di Django o una caratteristica di Python?

risposta

30

È possibile risolvere questo con il riorganizzare e data 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

Ero quasi tutto lì, ma non avevo capito che si poteva mescolare il filtro della data. Mille grazie per questo! Esattamente quello che stavo cercando. – saturdayplace

+0

buon dio, come non ho saputo di questo –

+0

è più veloce usare start_date.date se hai bisogno di 'la parte data' –

2

Questo sarebbe più semplice se si usassero le funzioni di formattazione della data del database per rimuovere i tempi (nella selezione). È quindi possibile raggruppare in base alla colonna formattata (utilizzando un alias di colonna).

Successivamente, è possibile utilizzare un ciclo con una piccola logica per trasporre i risultati su ciò che si desidera. Non ho ancora utilizzato sistema di template di Django, ma ecco quello che la logica sarà simile in 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 

Ci dovrebbe essere un modo straight-forward per convertire questo Django codice del modello.

+0

Posso raggruppare i dati, ma quale sarebbe la "piccola logica" all'interno del sistema di template? – ine

+0

Ho aggiunto un esempio. –

+0

Non sono convinto che tu possa farlo nei template di Django. Anche se tu potessi, non vorresti. È meglio farlo in: (1) il codice di visualizzazione o (2) un templatetag dove puoi usare python reale. – hughdbrown

15

itertools.groupby è il vostro caro, caro amico:

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 

Il codice di cui sopra stampa i seguenti:

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

Eccellente! itertools.groupby è proprio quello che stavo cercando. – ine

+0

Se avete intenzione di farlo nella vista, si desidera qualcosa di simile: "def sidebar_date_list(): da itertools importare GroupBy data = [datetime.date (post.created_at.year, post.created_at.month , 1) per post in Post.objects.filter (publish = 1) .order_by ('- created_at')] return {'months': [k per k, _ in groupby (dati)]} Si noti che il SQL deve essere ordinato per groupby() da usare. " Sollevato da qui: http://www.djangrrl.com/view/using-python-str-datetime-lists-and-sets-to-group-dates/ – hughdbrown

+0

O così se vuoi raggruppare per giorni: " def sidebar_date_list(): \t da itertools import groupby \t data = [datetime.date (post.created_at.year, post.created_at.month, post.created_at.day) per post in Post.objects.filter (publish = 1) .order_by ('- created_at')] \t return {'days': [k per k, _ in groupby (dati)]} " – hughdbrown

8

Queste sono tutte le risposte ragionevoli se l'OP potrebbe utilizzare pitone nel codice del template. (E per questo motivo, preferirei la soluzione itertools.groupby().) Ma non puoi usare python nel codice del template. Nel migliore dei casi, dovresti scrivere un templatetag che ha eseguito questa operazione. E c'è già un templatetag che fa questo.

Per fare il raggruppamento in Django all'interno del template, utilizzare Regroup:

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

Esempio sollevato da Django regroup documentation. riorganizzare è disponibile in django 0.96, 1.0 e 1.1, almeno.

Se mi hai dato un'idea di ciò che è passato al modello, potrei incidere un esempio che usa i tuoi dati.

Inoltre, c'è uno blog post in cui DjangoGrrl funziona esattamente con questa domanda.

+0

I linguaggi dei modelli tendono a fornire abbastanza degli stessi costrutti di linguaggio che è possibile convertire facilmente tra i due (condividono lo stesso bytecode di destinazione). –

+0

Non essere scortese, ma programmate su Django? Ai fini pratici, ci sono solo confronti rudimentali e operazioni di assegnazione. Guarda cosa è disponibile senza usare templatetags: http://docs.djangoproject.com/en/dev/topics/templates/ – hughdbrown

+0

Purtroppo, sto usando 0,96 ma questa è una grande risorsa per quelli su 1.0 o superiore! – ine

9

Nel fare rapporti sul set di dati più grandi itertools.group_by potrebbe essere troppo lento. In questi casi, faccio gestire il gruppo a 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')