Поворот данных и сложных аннотаций в Django ORM
ORM в Django позволяет нам легко аннотировать (добавлять поля) к запросам на основе связанных данных, хотя я не могу найти способ получить несколько аннотаций для разных фильтрованных подмножеств связанных данных.
Это задается в отношении 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, я могу более легко фильтровать данные динамически, не делая изворотливую вставку предложений WHERE в моем SQL.
Для "бонусных очков": как это сделать, когда поле поворота (status
в приведенном выше примере) было датой, и мы хотели, чтобы в столбцах были месяцы/недели/кварталы/дни?
Ответы
Ответ 1
У вас есть 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-алгоритмы, требующие сортировки как часть GROUP-BY.
Ответ 2
Django добавил много функциональности в ORM, поскольку этот вопрос изначально был задан. Ответ на вопрос о том, как свернуть данные с Django 1.8, заключается в использовании условных выражений Case/When . И есть стороннее приложение, которое сделает это за вас, PyPI и