Django - Группировка по двум столбцам для создания диаграммы со сложенными столбцами с помощью Highcharts
У меня есть Student модель для моего приложения Django, например, такая:
from django.db import models
class Student(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
major = models.CharField(max_length=100)
year = models.IntegerField()
Я пытаюсь создать диаграмму stacked column, используя Highcharts. На выходе получается вот так:
Идея заключается в том, что я хочу показать количество студентов, которые у нас есть в каждом году, с разбивкой по специализациям. Вот все данные для этого примера, за исключением имен:
[{'major': 'Computer Science', 'year': 1394}, {'major': 'Electrical Engineering', 'year': 1394}, {'major': 'Computer Science', 'year': 1394}, {'major': 'Chemistry Engineering', 'year': 1395}, {'major': 'Computer Science', 'year': 1396}, {'major': 'Computer Science', 'year': 1394}, {'major': 'English Literature', 'year': 1395}, {'major': 'English Literature', 'year': 1394}, {'major': 'Computer Science', 'year': 1395}, {'major': 'Chemistry Engineering', 'year': 1397}, {'major': 'Art', 'year': 1397}, {'major': 'Electrical Engineering', 'year': 1398}, {'major': 'Electrical Engineering', 'year': 1399}, {'major': 'English Literature', 'year': 1399}, {'major': 'Computer Science', 'year': 1400}, {'major': 'Chemistry Engineering', 'year': 1397}, {'major': 'English Literature', 'year': 1397}, {'major': 'Physics', 'year': 1393}, {'major': 'Physics', 'year': 1393}, {'major': 'Chemistry Engineering', 'year': 1392}, {'major': 'Persian Literature', 'year': 1392}, {'major': 'Computer Science', 'year': 1392}]
Я сгруппировал два столбца major и year,
grouped = (Student.objects
.values("major", "year")
.annotate(count=Count("id"))
.order_by("major", "year")
)
создал два списка различных лет и специальностей,
years = list(Student.objects
.order_by("year")
.values_list("year", flat=True)
.distinct()
)
majors = list(Student.objects
.order_by("major")
.values_list("major", flat=True)
.distinct()
)
и создали словарь специальностей с указанием количества студентов в каждом году.
data = {}
for major in majors:
if not major in data:
data[major] = {}
for year in years:
data[major][year] = 0
for group in grouped:
major = group["major"]
year = group["year"]
count = group["count"]
data[major][year] = count
Я сделал это, потому что мне нужно специально установить годы, в которых нет студентов, на ноль (для данной специальности), иначе порядок диаграммы будет искажен.
Наконец, я реструктурировал данные так, чтобы они соответствовали конфигурации Highchart для диаграмм со сложенными столбцами:
series = [{"name": d, "data": list(data[d].values())} for d in data]
print(series)
[{'name': 'Art', 'data': [0, 0, 0, 0, 0, 1, 0, 0, 0]}, {'name': 'Chemistry Engineering', 'data': [1, 0, 0, 1, 0, 2, 0, 0, 0]}, {'name': 'Computer Science', 'data': [1, 0, 3, 1, 1, 0, 0, 0, 1]}, {'name': 'Electrical Engineering', 'data': [0, 0, 1, 0, 0, 0, 1, 1, 0]}, {'name': 'English Literature', 'data': [0, 0, 1, 1, 0, 1, 0, 1, 0]}, {'name': 'Persian Literature', 'data': [1, 0, 0, 0, 0, 0, 0, 0, 0]}, {'name': 'Physics', 'data': [0, 2, 0, 0, 0, 0, 0, 0, 0]}]
Это работает, и в результате получается изображение, которое я разместил выше. Но мне кажется, что я делаю много ненужной постобработки для достижения этого (два цикла for для создания словаря data).
Итак, мой вопрос заключается в следующем: есть ли способ добиться тех же результатов с помощью запроса к базе данных, чтобы минимизировать постобработку?
