2016-05-19 6 views
1

Ich habe zwei Django-Querysets, die ich basierend auf ihrem Datumsattribut zusammenführen möchte. Nun, es ist nicht wirklich Django Frage, aber ich versuche es so klar wie möglich zu erklären.
Ich muss Einträge basierend auf zwei Datenattribute gruppieren. Lassen Sie uns sagen ich ein Modell haben:Wie man eine Liste von Dicts basierend auf dem Attribut dict zusammenfasst

class User(models.Model): 
    start_date = models.DateField(blank=True, null=True) 
    end_date = models.DateField(blank=True, null=True) 
    ... 

Jetzt müssen Gruppe I für Monat diese Einträge (wie viele Nutzer auf 2010 etc Mai gestartet):

truncate_start_date = connection.ops.date_trunc_sql('month', 'start_date') 
report_start = User.objects.exclude(start_date__isnull=True)\ 
    .extra({'month': truncate_start_date}).values('month')\ 
    .annotate(start_count=Count('pk')).order_by('-month') 

und ich habe gleiche Abfrage für end_date:

truncate_end_date = connection.ops.date_trunc_sql('month', 'end_date') 
report_end = Employee.objects.exclude(end_date__isnull=True)\ 
    .extra({'month': truncate_end_date}).values('month')\ 
    .annotate(end_count=Count('pk')).order_by('-month') 

Jetzt ist es das, was report_start wie folgt aussieht:

[{'start_count': 33, 'month': datetime.datetime(2016, 5, 1, 0, 0, tzinfo=<UTC>)}, 
{'start_count': 79, 'month': datetime.datetime(2016, 4, 1, 0, 0, tzinfo=<UTC>)}, 
{'start_count': 72, 'month': datetime.datetime(2016, 3, 1, 0, 0, tzinfo=<UTC>)}, 
... ] 

Nun, wie füge ich diese zwei Listen von dicts zu einem basierend auf month zusammen? Ich habe versucht chain, aber es gab doppelte month Datensätze.
Ich mag bekommen:

[{'start_count': 33, 'end_count': None, 'month': datetime.datetime(2016, 5, 1, 0, 0, tzinfo=<UTC>)}, 
{'start_count': 79, 'end_count': 2, 'month': datetime.datetime(2016, 4, 1, 0, 0, tzinfo=<UTC>)}, 
{'start_count': 72, 'end_count': 8, 'month': datetime.datetime(2016, 3, 1, 0, 0, tzinfo=<UTC>)}, 
... ] 

Was ich in der Lage war, mit zu kommen war, es zu ändern zurück zur Liste dicts dict und dann. Aber ich glaube, das ist keine sehr elegante Lösung und es muss einen besseren Weg geben, diesen pythischen Weg zu schreiben.
Irgendwelche Ideen? Hier ist mein hässlicher Code:

d = dict() 
for end in report_end: 
    d[end['month']] = {"end_count": end['end_count']} 
for start in report_start: 
    if start['month'] in d.keys(): 
     d[start['month']]["start_count"] = start['start_count'] 
    else: 
     d[start['month']] = {"start_count": start['start_count']} 
result = [] 
for key, i in d.items(): 
    result.append({'month': key, 
        'start_count': i['start_count'] if 'start_count' in i.keys() else None, 
        'end_count': i['end_count'] if 'end_count' in i.keys() else None}) 

Antwort

1

datetime ist hashable, so dass Sie es als Schlüssel zu einem dict speichern können und leicht verschmelzen. Hier ist eine kleine Testlösung mit itemgetter. Dies setzt voraus, dass Ihre Zeitstempel in jeder Liste von dict s eindeutig sind.

from operator import itemgetter 
import datetime 


starts = [ 
{'start_count': 33, 'month': datetime.datetime(2016, 5, 1, 0, 0)}, 
{'start_count': 79, 'month': datetime.datetime(2016, 4, 1, 0, 0)}, 
{'start_count': 72, 'month': datetime.datetime(2016, 3, 1, 0, 0)} 
] 

# dummy data 
ends = [ 
{'end_count': 122, 'month': datetime.datetime(2016, 5, 1, 0, 0)}, 
{'end_count': 213, 'month': datetime.datetime(2016, 4, 1, 0, 0)}, 
{'end_count': 121, 'month': datetime.datetime(2016, 3, 1, 0, 0)} 
] 


starts = dict(map(itemgetter('month', 'start_count'), starts)) 
ends = dict(map(itemgetter('month', 'end_count'), ends)) 


joined = [{'month': m, 'start_count': s, 'end_count': ends.get(m, None)} 
    for m, s in starts.items()] 
+0

nette Lösung. Was, wenn es einen "Monat" in den Enden gibt, der nicht in Starts vorhanden ist? Wird es in der verbundenen Liste sein? – Lucas03

+0

Nein, Sie können wie folgt ändern: Nehmen Sie die Vereinigung von Monatsschlüsseln, iterieren Sie diese durch Listenverständnis und verwenden Sie .get on starts. –

+1

ok, danke. Ich dachte, das wäre leicht zu schreiben mit einigen Itertools Funktionen in niedrigeren Zeilen, aber das ist auch gut! – Lucas03

Verwandte Themen