【发布时间】:2020-12-12 09:24:33
【问题描述】:
我需要计算拳击比赛期间运动员的排名。在我的模型中,我会跟踪每场比赛的结果以及为每个结果分配给每位运动员的分数。
class Member(models.Model):
surname = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
class Tournament(models.Model):
name = models.CharField(max_length=200)
class TrophyRule(models.Model):
win = models.IntegerField()
loose = models.IntegerField()
draw = models.IntegerField()
class Ring(models.Model):
code = models.CharFieldmax_length=1)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
class Match(models.Model):
ring = models.ForeignKey(Ring, null=True, on_delete=models.SET_NULL)
winner = models.CharField(max_length=20, null=True, blank=True)
trophy_rule = models.ForeignKey(TrophyRule, on_delete=models.SET_NULL, null=True)
red_member = models.ForeignKey(Member, related_name='reds', on_delete=models.SET_NULL, null=True)
red_count_ranking = models.BooleanField(default=True)
blue_member = models.ForeignKey(Member, related_name='blues', on_delete=models.SET_NULL, null=True)
blue_count_ranking = models.BooleanField(default=True)
基于这个模型,我需要将运动员在红角时获得的积分与运动员在蓝角时获得的积分相加。结果应该是一个包含所有成员及其总点数的查询集。
为了实现这一点,我从计算红角运动员获得的分数开始:
from apps.members.models import Member
from django.db.models import Case, Sum, When, Q
red = Member.objects.filter(reds__ring__tournament_id=11402).annotate(
points=Case(
When(Q(reds__winner='red') & Q(reds__red_count_ranking=True), then='reds__trophy_rule__win'),
When(Q(reds__winner='draw') & Q(reds__red_count_ranking=True), then='reds__trophy_rule__draw'),
When(Q(reds__winner='blue') & Q(reds__red_count_ranking=True), then='reds__trophy_rule__loose'),
),
)
我对蓝色角落的运动员获得的积分也做了同样的事情:
blue = Member.objects.filter(blues__ring__tournament_id=11402).annotate(
points=Case(
When(Q(blues__winner='blue') & Q(blues__blue_count_ranking=True), then='blues__trophy_rule__win'),
When(Q(blues__winner='draw') & Q(blues__blue_count_ranking=True), then='blues__trophy_rule__draw'),
When(Q(blues__winner='red') & Q(blues__blue_count_ranking=True), then='blues__trophy_rule__loose'),
),
)
现在,我需要将这两个查询结合起来,并对每个运动员的分数求和。这是我目前卡住的部分。
我尝试使用转换为 SQL UNION 的 union():
red.union(blue)
如果我有 4 个匹配项,则使用 union() 我会得到一个包含 8 个成员(4 个红色和 4 个蓝色)的查询集,这正是我正在寻找的。不幸的是,当我尝试计算最终的点数(运动员为红色时的点数+运动员为蓝色时的点数)时,我触发了错误:在 union() 后调用 QuerySet.annotate() 不受支持(根据@ 987654321@).
red.union(blue).annotate(Sum('points'))
还有其他方法可以使用 Django ORM 实现这一点吗?如果没有必要,我不想恢复到原始 SQL。
【问题讨论】:
标签: django django-queryset union django-annotate