2011-05-11 9 views
12

El ORM en Django nos permite anotar fácilmente (agregar campos) conjuntos de consultas basados ​​en datos relacionados, sin embargo, no puedo encontrar la manera de obtener múltiples anotaciones para diferentes subconjuntos filtrados de datos relacionados.Datos pivotantes y anotaciones complejas en Django ORM

Esto se está preguntando en relación con django-helpdesk, un rastreador de problemas con código abierto Django. Es necesario disponer de datos pivotan así por la cartografía y los propósitos de informes

Considere estos modelos:

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) 

Y este conjunto de datos:

colas de espera:

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

Problemas:

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

Me gustaría ver una anotación/mirada algo agregada como esto:

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

Ésta es básicamente una tabla de referencias cruzadas o de pivote, en la jerga de Excel. Actualmente estoy creando esta salida usando algunas consultas SQL personalizadas, sin embargo, si puedo pasar al uso del ORM de Django, puedo filtrar los datos de manera más fácil de forma dinámica sin hacer una inserción dudosa de las cláusulas WHERE en mi SQL.

Para "puntos de bonificación": ¿Cómo se haría esto cuando el campo pivote (status en el ejemplo anterior) era una fecha, y queríamos que las columnas fueran meses/semanas/trimestres/días?

Respuesta

6

Tiene Python, úselo.

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

Ahora su objetivo summary tiene cola, el estado como una llave de dos tupla. Puede visualizarlo directamente, usando varias técnicas de plantilla.

O bien, puede reagruparlo en una estructura de tabla, si es más simple.

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

Tiene muchas técnicas de Python para hacer tablas dinámicas.

Si mides, es posible que una solución en su mayoría de Python como esta sea en realidad más rápida que una solución SQL pura. ¿Por qué? Las asignaciones pueden ser más rápidas que los algoritmos SQL que requieren una ordenación como parte de GROUP-BY.

+1

Esta solución se derrumbará si la tabla de Problemas es grande y no puede considerarse general. – JohnnyM

+0

Para cualquiera que lea esto algunos años después: Obtengo el objeto 'collections.defaultdict 'no tiene atributo' count'' con python3 también hay un error tipográfico en' summary.count (q.'closed ') ' –

2

Django ha agregado mucha funcionalidad al ORM ya que esta pregunta se realizó originalmente. La respuesta a cómo pivotar datos desde Django 1.8 es usar el Caso/Cuándo conditional expressions. Y hay una aplicación de terceros que lo hará por usted, PyPI y documentation

Cuestiones relacionadas