Аннотировать над полем промежуточной модели Джанго - PullRequest
0 голосов
/ 26 июня 2018

У меня есть следующая схема:

class User(AbstractUser):
    pass

class Task(models.Model):
    pass

class Contest(models.Model):
    tasks = models.ManyToManyField('Task',
                               related_name='contests',
                               blank=True,
                               through='ContestTaskRelationship')

    participants = models.ManyToManyField('User',
                                      related_name='contests_participated',
                                      blank=True,
                                      through='ContestParticipantRelationship')

class ContestTaskRelationship(models.Model):
    contest = models.ForeignKey('Contest', on_delete=models.CASCADE)
    task = models.ForeignKey('Task', on_delete=models.CASCADE)
    cost = models.IntegerField()


class ContestParticipantRelationship(models.Model):
    contest = models.ForeignKey('Contest', on_delete=models.CASCADE)
    user = models.ForeignKey('User', on_delete=models.CASCADE)
    task = models.ForeignKey('Task', on_delete=models.CASCADE, related_name='contests_participants_relationship')
    is_solved = models.BooleanField()

Теперь у меня есть объект contest, и мне нужно выбрать все задачи через поле tasks, rach с примечанием количества пользователей решило его. Итак, мне нужно посчитать число ContestParticipantRelationship с необходимыми task, необходимыми contest и is_solved, установленными в True. Как сделать такой запрос?

1 Ответ

0 голосов
/ 26 июня 2018

Возможно что-то вроде:

from django.db.models import IntegerField, Value, Sum
from django.db.models.functions import Cast, Coalesce


Task.objects.filter(
    contests__contest=some_contest,
).annotate(
    nsolved=Cast(Coalesce(
        Sum('contests_participants_relationship__is_solved'), Value(0)
    ),IntegerField())
)

Итак, здесь мы сначала отфильтровываем тот факт, что конкурс на задание составляет some_contest. И затем мы выполняем Sum(..) над is_solved столбцом. Поскольку существуют угловые случаи, когда это может быть NULL (в случае, если нет пользователя, который предпринял попытку и т. Д.), Тогда мы конвертируем его в 0, и, кроме того, мы приводим его к IntegerField, поскольку в противном случае некоторые экземпляры могут быть помечены True и False в случае, если ноль или один пользователь решает это.

...