Django ORM: SUM сгруппированных MAX

Я пытаюсь перевести этот SQL запрос:

SELECT user_id, SUM(max_score) 
FROM (SELECT user_id, MAX(score) AS max_score
      FROM submissions 
      GROUP BY exercise_id, user_id) AS subquery 
GROUP BY user_id;

где таблица submissions имеет столбцы user_id, exercise_id и score.

Перевод внутреннего подзапроса приводит к:

        subquery = (
            Submission.objects
            .values("exercise", "user")
            .annotate(max_score=Max("score"))
            .values("user", "max_score")
        )

с таким набором запросов:

<QuerySet [{'user': 1, 'max_score': 27}, 
           {'user': 2, 'max_score': 50}, 
           {'user': 1, 'max_score': 16}, 
           {'user': 3, 'max_score': 14}, 
           {'user': 1, 'max_score': 14}, 
           ...]>

Однако, когда я пытаюсь суммировать их по пользователям, используя subquery.annotate(total_score=Sum("max_score")), я получаю:

FieldError: Cannot compute Sum('max_score'): 'max_score' is an aggregate

Как я могу реализовать это в Django ORM вместо неэффективного решения вроде этого:

        scores = defaultdict(int)
        for row in subquery:
            scores[row['user']] += row['max_score']
result = subquery.aggregate(total_score=Sum("max_score"))

Для доступа к значению в результате:

result['total_score']

annotate возвращает строки со специальным атрибутом, установленным на каждой строке, который вы указываете в аргументе метода, но он все равно возвращает строки (QuerySet). Метод aggregate возвращает результат агрегации - одно значение.

Дайте мне знать, если это работает :)

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