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. На выходе получается вот так:

chart

Идея заключается в том, что я хочу показать количество студентов, которые у нас есть в каждом году, с разбивкой по специализациям. Вот все данные для этого примера, за исключением имен:

[{'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).


Итак, мой вопрос заключается в следующем: есть ли способ добиться тех же результатов с помощью запроса к базе данных, чтобы минимизировать постобработку?

Вернуться на верх