Django计算匹配分数在合并后注释查询的解决方法

问题描述

我需要计算拳击比赛中运动员的排名。在我的模型中,我跟踪每次比赛的结果以及每个结果归属于每个运动员的分数。

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,blank=True)
    trophy_rule = models.ForeignKey(TrophyRule,on_delete=models.SET_NULL,null=True)
    red_member = models.ForeignKey(Member,related_name='reds',null=True)
    red_count_ranking = models.BooleanField(default=True)
    blue_member = models.ForeignKey(Member,related_name='blues',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'),)

现在,我需要将两个查询结合起来,并为每个运动员加分。这是我目前停留的部分。

我尝试使用union()转换为sql UNION:

red.union(blue)

如果我有4个匹配项,则使用union()会得到一个包含8个成员(4个红色和4个蓝色)的查询集,这正是我要寻找的。不幸的是,当我尝试计算最终的点数(运动员是红色的点+运动员是蓝色的点)时,我触发了错误不支持在union()之后调用QuerySet.annotate()(按照{ {3}})。

red.union(blue).annotate(Sum('points'))

是否还有另一种方法可以通过Django ORM实现这一目标?我宁愿不要在不必要的情况下恢复为原始sql

解决方法

这可能在单个请求中(未经验证的代码):

from django.db.models import Case,When,Q,F

members = Member.objects.filter(Q(reds__ring__tournament_id=11402)|Q(blues__ring__tournament_id=11402)).annotate(
    red_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_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'),points=F('red_points') + F('blue_points')
)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...