我有以下方案:
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。如何进行这样的查询?
可能是这样的:
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
注释,以防零或一个用户解决它。