Нахождение общего балла из максимального балла конкретного пользователя в django orm

У меня есть функция, которая получает два параметра (contest_id, user_id), как я могу получить максимальную оценку каждой задачи в данном конкурсе для данного пользователя и затем суммировать все эти максимальные оценки? каждая задача может иметь ноль или много представленных оценок.

например: (problem_id,submitted_score) --> (1, 80), (1, 100), (2, 150), (2, 200), (3, 220), (3, 300)

Ожидаемый результат для этого примера должен быть 600, 100 + 200 + 300.

Модели:

class Contest(models.Model):
    name = models.CharField(max_length=50)
    holder = models.ForeignKey(User, on_delete=models.CASCADE)
    start_time = models.DateTimeField()
    finish_time = models.DateTimeField()
    is_monetary = models.BooleanField(default=False)
    price = models.PositiveIntegerField(default=0)
    problems = models.ManyToManyField(Problem)
    authors = models.ManyToManyField(User, related_name='authors')
    participants = models.ManyToManyField(User, related_name='participants')

class Problem(models.Model):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=1000)
    writer = models.ForeignKey(User, on_delete=models.DO_NOTHING)
    score = models.PositiveIntegerField(default=100)

class Submission(models.Model):
    submitted_time = models.DateTimeField()
    participant = models.ForeignKey(User, related_name="submissions", on_delete=models.DO_NOTHING)
    problem = models.ForeignKey(Problem, related_name="submissions", on_delete=models.CASCADE)
    code = models.URLField(max_length=200)
    score = models.PositiveIntegerField(default=0)

Вы можете аннотировать Problems максимальным score из связанных Submissions, а затем суммировать их, так:

from django.db.models import Max, Sum

Problem.objects.filter(
    contest__id=contest_id,
    submissions__participant_id=user_id
).annotate(
    max_score=Max('submissions__score')
).aggregate(
    total=Sum('max_score')
)

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

SELECT SUM(max_score)
FROM (
    SELECT MAX(submission.score) AS max_score
    FROM problem
    INNER JOIN contest_problems ON problem.id = contest_problems.problem_id
    INNER JOIN submission ON problem.id = submission.problem_id
    WHERE contest_problems.contest_id = contest_id
      AND submission.participant_id = 1
    GROUP BY problem.id
) subquery

Если для любого Submission для данного контекста не существует связанных Problem, то вместо NULL будет возвращено None/0.

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