在Django上建立排名系统

时间:2019-05-24 00:08:15

标签: django django-models django-views

我有一个具有以下模型的Django足球应用,我想创建一个查询集(或其他方式)以在模板上建立“排名”表(作为上下文传递):

  • 圆形(round_number,round_name)
  • 游戏(回合,team1,team2,进球,失误)
  • 团队(名称)
  • 玩家(姓名,团队)
  • 目标(游戏,玩家)
  • 故障(游戏,玩家)

在这些模型具有这些字段的情况下,如何建立具有以下信息的排名表?

团队|获胜|损失玩过的游戏

1 个答案:

答案 0 :(得分:0)

数据模型的结构使某些事情变得不直观,因此,如果在那里有灵活性,则可能需要考虑进行更改。

例如,如果您想获取游戏列表并知道谁赢得了比赛,这并非易事,因为游戏表中没有用于获胜队伍的列,也没有关于如何赢得比赛的信息每个团队得分很多。相反,您必须加入目标,然后加入玩家,然后加入玩家团队。 (警告:我无法测试此代码,它非常复杂,可能会出现错误。)

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

games = Game.objects.annotate(
    team1_goal_count=Count('goals', filter=Q(goals__player__team=F('team1'), distinct=True),
    team2_goal_count=Count('goals', filter=Q(goals__player__team=F('team2'), distinct=True),
    result=Case(When(Q(team1_goal_count__gt=team2_goal_count), then=F('team1')),
                When(Q(team2_goal_count__gt=team1_goal_count), then=F('team2')),
                default=None)
)

以上内容将为您提供一个游戏查询集,并在result列中为每支球队的进球数和获胜球队的ID(如果是平局,则为null

如果要获取按获胜率排序其赢/输/平局记录的球队名单,则必须加入游戏并类似地计算得分(注意,这是如此复杂,我不知道如果它甚至按我所写的一样起作用):

from django.db.models import Subquery, OuterRef
# Use the `games` query from above
scored_games_1 = games.filter(team1_id=OuterRef('pk'))
scored_games_2 = games.filter(team2_id=OuterRef('pk'))

# Need to group by the OuterRef('pk')
scored_games_1 = scored_games_1.values('team1')
scored_games_2 = scored_games_2.values('team2')

# Annotate the counts and select on that column
scored_games_1 = scored_games_1.annotate(count=Count('pk')).values('count')
scored_games_2 = scored_games_2.annotate(count=Count('pk')).values('count')

won_q = Q(result=F('pk'))
lost_q = Q(result__isnull=False) & ~Q(result=F('pk'))
tied_q = Q(result__isnull=True)
teams = Team.objects.annotate(
    games_won=Subquery(scored_games_1.filter(won_q)) + Subquery(scored_games_2.filter(won_q)),
    games_lost=Subquery(scored_games_1.filter(lost_q)) + Subquery(scored_games_2.filter(lost_q)),
    games_tied=Subquery(scored_games_1.filter(tied_q) + Subquery(scored_games_2.filter(tied_q)),
    winning_percentage=F('games_won') / (F('games_won') + F('games_lost') + F('games_tied'))
).order_by('-winning_percentage')

Game中包含一列获胜团队的ID是非规范化,这使得上述所有操作都变得更加简单。将GameTeam建立多对多关系(即使只有两个团队)也将使事情变得容易。