Django аннотирование по нескольким записям forignkeys

Я работаю над системой KPI, в которой каждый менеджер может задавать конкретные вопросы каждому пользователю и отвечать на них каждый месяц от 1 до 10 У нас есть 4 отдела, и каждый отдел говорит, что у него есть 4 вопроса эти ответы должны быть вычислены, чтобы вернуть % количество для каждого отдела

Модели


# question to answer every month

class Question(models.Model):
    department = models.CharField(max_length=100, choices=USER_TYPE)
    question = models.CharField(max_length=100)

    def __str__(self):
        return f"{self.question}"

# create every 01-month celery

class Kpi(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="kip_for")
    created_at = models.DateField()

    class Meta:
        unique_together = ("user", "created_at")

    def __str__(self):
        return f"{self.user} for Month {self.created_at.month}"

# group the answers by department

class DepartmentsKPI(models.Model):
    department = models.CharField(max_length=100, choices=USER_TYPE)
    kpi = models.ForeignKey(
        Kpi, on_delete=models.CASCADE, related_name="department_kpi"
    )

class Answer(models.Model):
    question = models.ForeignKey(
        Question, on_delete=models.CASCADE, related_name="answer_for"
    )
    score = models.PositiveSmallIntegerField(default=0)
    comment = models.TextField(null=True, blank=True)
    kpi_answers = models.ForeignKey(
        DepartmentsKPI,
        on_delete=models.CASCADE,
        related_name="department_answers",
    )

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

def get_kpi_range(*, year, month):
    queryset = (
        KPIRepository.filter_kpis(
            created_at__year=year,
            created_at__month=month,
        )
        .prefetch_related("department_kpi__department_answers")
        .annotate(
            score=Sum("department_kpi__department_answers__score")
            / Count("department_kpi__department_answers"),
            department=F("department_kpi__department"),
        )
        .values("id", "score", "department", username=F("user__username"))
    )

    grouped = [
        {"username": username, "kpis": list(instances)}
        for username, instances in itertools.groupby(queryset, lambda x: x["username"])
    ]

    return grouped

Однако это не позволяет обрабатывать несколько записей для одного и того же пользователя. Если я запрашиваю все KPI за один год, результат становится беспорядочным.

Кроме того, если я хочу построить графики, я не могу вернуть данные для каждого пользователя, сгруппированные по каждому месяцу года

Текущий результат с grouped выше

[
    {
        "username": "xxxxx",
        "kpis": [
            {
                "department": "HR",
                "score": 5
            },
            {
                "department": "IT",
                "score": 6
            },
            {
                "department": "QUALITY",
                "score": 4
            },
            {
                "department": "WFM",
                "score": 6
            }
        ]
    },
    {
        "username": "ahmed",
        "kpis": [
            {
                "department": "IT",
                "score": 6
            }
        ]
    }
]

Без grouped

[
    [
        {
            "id": 7,
            "score": 5,
            "department": "HR",
            "username": "xxx"
        },
        {
            "id": 7,
            "score": 6,
            "department": "IT",
            "username": "xxx"
        },
        {
            "id": 7,
            "score": 4,
            "department": "QUALITY",
            "username": "xxx"
        },
        {
            "id": 7,
            "score": 6,
            "department": "WFM",
            "username": "xxx"
        },
        {
            "id": 8,
            "score": 6,
            "department": "IT",
            "username": "ahmed"
        }
    ]
]
Вернуться на верх