在Django ORM中对数据进行透视和复杂注释
Django中的ORM(对象关系映射)让我们可以很方便地给查询结果添加一些额外的信息,这些信息是基于相关数据的。不过,我找不到办法来为不同的过滤数据子集添加多个这样的额外信息。
这个问题是关于django-helpdesk的,这是一个开源的、基于Django的故障单追踪系统。我需要将数据整理成这样,以便于制作图表和报告。
考虑这些模型:
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)
还有这个数据集:
队列:
ID | Name
---+------------------------------
1 | Product Information Requests
2 | Service Requests
问题:
ID | Queue | Status
---+-------+---------
1 | 1 | open
2 | 1 | open
3 | 1 | closed
4 | 2 | open
5 | 2 | closed
6 | 2 | closed
7 | 2 | closed
我希望看到的额外信息/汇总结果大概是这样的:
Queue ID | Name | open | closed
---------+-------------------------------+------+--------
1 | Product Information Requests | 2 | 1
2 | Service Requests | 1 | 3
这基本上就是一个交叉表或数据透视表,用Excel来说就是这个意思。我现在是通过一些自定义的SQL查询来生成这个结果,但如果能用Django的ORM来实现,就能更轻松地动态过滤数据,而不需要在SQL中插入复杂的WHERE条件。
如果想要“额外加分”:如果数据透视的字段(上面例子中的status
)是日期,我们想要的列是按月/周/季度/天来划分,应该怎么做呢?
2 个回答
5
你有Python,就用它吧。
from collections import defaultdict
summary = defaultdict( int )
for issue in Issues.objects.all():
summary[issue.queue, issue.status] += 1
现在你的 summary
对象有一个队列和状态,组成了一个二元组的键。你可以直接显示它,使用各种模板技巧。
或者,如果这样更简单的话,你也可以把它重新整理成一个像表格一样的结构。
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') )
你有很多很多的Python技巧可以用来制作数据透视表。
如果你进行测量,你可能会发现,像这样的主要用Python的解决方案实际上比纯SQL的解决方案更快。为什么呢?因为映射操作可能比需要排序的SQL算法在进行分组时要快。