2011-05-11 13 views
12

L'ORM in Django ci consente di annotare facilmente (aggiungere campi a) serie di query in base a dati correlati, ma non riesco a trovare un modo per ottenere più annotazioni per diversi sottoinsiemi filtrati di dati correlati.Dati di rotazione e annotazioni complesse in Django ORM

Questo è richiesto in relazione a django-helpdesk, un tracker trouble-ticket open source basato su Django. Ho bisogno di avere i dati imperniati come questo per la creazione di grafici e le finalità di reporting

Considerare questi modelli:

CHOICE_LIST = (
    ('open', 'Open'), 
    ('closed', 'Closed'), 
) 

class Queue(models.model): 
    name = models.CharField(max_length=40) 

class Issue(models.Model): 
    subject = models.CharField(max_length=40) 
    queue = models.ForeignKey(Queue) 
    status = models.CharField(max_length=10, choices=CHOICE_LIST) 

E questo insieme di dati:

Code:

ID | Name 
---+------------------------------ 
1 | Product Information Requests 
2 | Service Requests 

Issues:

ID | Queue | Status 
---+-------+--------- 
1 | 1  | open 
2 | 1  | open 
3 | 1  | closed 
4 | 2  | open 
5 | 2  | closed 
6 | 2  | closed 
7 | 2  | closed 

Mi piacerebbe vedere un'annotazione/aggregato simile a questa:

Queue ID | Name       | open | closed 
---------+-------------------------------+------+-------- 
1  | Product Information Requests | 2 | 1 
2  | Service Requests    | 1 | 3 

Questo è fondamentalmente una tabella a campi incrociati o pivot, in Excel gergo. Attualmente sto costruendo questo output usando alcune query SQL personalizzate, tuttavia se posso passare all'utilizzo di Django ORM, posso più facilmente filtrare i dati in modo dinamico senza fare il dodgy insertion delle clausole WHERE nel mio SQL.

Per "punti bonus": Come si farebbe questo quando il campo di rotazione (status nell'esempio sopra) era una data e volevamo che le colonne fossero mesi/settimane/quarti/giorni?

risposta

6

Hai Python, usalo.

from collections import defaultdict 
summary = defaultdict(int) 
for issue in Issues.objects.all(): 
    summary[issue.queue, issue.status] += 1 

Ora l'oggetto summary ha coda, lo stato come una chiave a due tuple. Puoi visualizzarlo direttamente, usando varie tecniche di template.

Oppure, è possibile raggrupparlo in una struttura simile a una tabella, se è più semplice.

table = [] 
queues = list(q for q,_ in summary.keys()) 
for q in sorted(queues): 
    table.append(q.id, q.name, summary.count(q,'open'), summary.count(q.'closed')) 

Hai un sacco di tecniche Python per fare tabelle pivot.

Se si misura, è possibile che una soluzione per lo più Python come questa sia effettivamente più veloce di una soluzione SQL pura. Perché? Le mappature possono essere più veloci degli algoritmi SQL che richiedono un ordinamento come parte di GROUP-BY.

+1

Questa soluzione si sgretolerà se la tabella Issues è grande e difficilmente può essere considerata come generale. – JohnnyM

+0

Per chi legge questo qualche anno più tardi: ottengo che l'oggetto 'collections.defaultdict 'non ha attributo' count'' con python3 c'è anche un refuso su' summary.count (q.'closed ') ' –

2

Django ha aggiunto molte funzionalità all'ORM poiché questa domanda era stata inizialmente richiesta. La risposta a come ruotare i dati da quando Django 1.8 utilizza la custodia/Quando conditional expressions. E c'è un'app di terze parti che lo farà per te, PyPI e documentation