我如何计算django

时间:2017-04-17 09:09:15

标签: python django aggregate

对于一个小项目,我有一个匹配和结果的注册表。每场比赛都在球队之间进行(可能是单人球队),并且有一个胜利者。我有MatchTeam模型,加上MatchTeam模型。这看起来像(简化)见下面的注释

class Team(models.Model):
    ...

class Match(models.Model):
    teams = ManyToManyField(Team, through='MatchTeam')
    ...

class MatchTeam(models.Model):
    match = models.ForeignKey(Match, related_name='matchteams',)
    team = models.ForeignKey(Team)
    winner = models.NullBooleanField()
    ...

现在我想在比赛中做一些统计数据,从查找谁是最能打败你的人开始。我至少不能有效地确定如何做到这一点。

在SQL中(这里只是近似),我的意思是这样的:

SELECT their_matchteam.id, COUNT(*) as cnt
FROM matchteam AS your_mt  
JOIN matchteam AS their_mt ON your_mt.match_id = their_mt.match_id
WHERE your.matchteam.id IN <<:your teams>> 
  your_matchteam.winner = false
GROUP BY their_matchteam.team_id
ORDER BY cnt DESC

(这也需要&#34;他们的_tt不是你的_tt&#34; btw条款,但概念很明确,对吗?)

虽然我没有将其作为SQL进行测试,但它只是为了深入了解我正在寻找的内容:我想通过Django聚合找到这个结果。

根据手册,我可以使用聚合注释结果,在本例中为Count。正如我在SQL中所做的那样MatchTeams直接加入MatchTeams可能是一种捷径,因为它应该&#39;介于两者之间Match?至少,我不知道如何将其翻译成Django

所以也许我需要为我的团队找到某些匹配项,然后使用其他团队的计数对它们进行注释?但是另一支球队&#39;是什么?

快速撰写如下:

nemesis = Match.objects \
        .filter(matchteams__in=yourteams) \
        .annotate(cnt=Count('<<otherteam>>')).order_by('-cnt')[0]

如果这是正确的轨道,我该如何定义Count。 如果它不是正确的轨道,那是什么?

原样,这完全是关于团队而不是用户。这只是为了简单起见:)

另一个问题可能是:我是否应该使用Django ORM的东西,或者我最好只添加SQL?这有一个明显的缺点,就是你要编写非常通用的代码(这甚至可能吗?)或修复你的DB后端。如果不需要,我想避免这种情况。

关于模型:我真的想了解我可以改变模型以使其变得更好,但我无法真正看到没有缺点的解决方案。让我试着解释一下:

我想支持任意数量的球队比赛,例如5队比赛。这意味着我有多对多的关系,而不是一个例如1个匹配2个团队的关系。如果是这种情况,您可以进行非规范化并将获胜者/分数放入团队表中。但事实并非如此。

关于一个团队的结果的额外数据(例如他们的最终得分,他们的时间)根据定义是该关系的属性。它不能进入​​team表(因为它将是每个匹配,你可以有一个未定义的匹配数量),并且由于相同的原因,它不能进入​​匹配表,并作必要的修改。

示例:我有A,B,C,D和E队比赛。 A队和B队有10分,其余都有0分。我想节省积分,A队和B队是这场比赛的赢家。

所以评论表明我需要一个更好的&#39;设计,无论如何,如果你有一个我很乐意看到它,但如果你想支持我支持的东西,它会变得很难。

最后一句话:这个数据可以在SQL中轻松检索,所以这个模型对我来说似乎很好:我只是在Django的初学者中过多而无法在Django&#39;是ORM!

2 个答案:

答案 0 :(得分:5)

有趣的问题!我想我有答案(让团队最能打败yourteams):

Team.objects.get( # the expected result is a team
    pk=list( # filter out yourteams
        filter(lambda x: x not in [ y.id for y in yourteams ],
            list( 
                Match.objects # search matches
                .filter(matchteams__in=yourteams) # in which you were involved
                .filter(matchteams__winner=False) # that you loose
                .annotate(cnt=Count('teams')) # and count them
                .order_by('-cnt') # sort appropriately
                .values_list('teams__id', flat=True) # finally get only pks
            )
        )
    )[0] # take the first item that should be the super winner
)

我没有明确地测试它,但如果不起作用,我认为它可能是正确的轨道。

答案 1 :(得分:0)

你可以做这样的事情

matches_won_aginst_my_team = MatchTeam.objects.filter(team=my_team, winner=False).select_related(matches)    
teams_won_matches_aginst_my_team = matches_won_aginst_my_team.filter(winner=True).values_list('matchteams__team')

但正如所建议的那样,你可以更好地建模 我会在MatchModel中保存两个字段:home_team,away_team。
更简单,更具指示性。