You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中实现按游戏阶段统计玩家得票数的QuerySet

问题描述

我正在开发一款包含玩家互投机制的游戏,已在models.py中定义相关核心模型:

class Game(models.Model):
  gamecode = ShortUUIDField(length=4, max_length=4, unique=True)
  phasenumber = models.IntegerField(default=1)
  isActive = models.BooleanField(default=True)

class Player(models.Model):
  game = models.ForeignKey(Game, on_delete=models.CASCADE)
  user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
  isPlaying = models.BooleanField(default=True)

class PlayerVote(models.Model):
  byplayer = models.ForeignKey(Player, on_delete=models.CASCADE)
  forplayer = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="voteforplayer")
  gamephasenumber = models.IntegerField()
  timestamp = models.DateTimeField(auto_now_add=True)

用户加入游戏时会在Player模型生成记录,玩家投票时会在PlayerVote模型添加投票人(byplayer)、被投票人(forplayer)及当前游戏阶段(gamephasenumber)的记录。

我希望生成包含每位玩家当前游戏阶段得票数的QuerySet,目前已实现获取全阶段得票数的代码:

playerswithvotes = Player.objects.select_related('game').filter(game = activegame.game, game__phasenumber = activegame.game.phasenumber, isPlaying = True).annotate(votesreceived=Count('voteforplayer')).order_by('-votesreceived')

但无法实现仅统计当前阶段得票数的功能,尝试以下写法均未成功:

votesthisround = Count("playervote", filter=Q(playervote__gamephasenumber = activegame.game.phasenumber))
playerswithvotes = Player.objects.select_related('game').filter(game = activegame.game, game__phasenumber = activegame.game.phasenumber, isPlaying = True).annotate(votesreceived=votesthisround).order_by('-votesreceived')
playerswithvotes = Player.objects.select_related('game').filter(game = activegame.game, game__phasenumber = activegame.game.phasenumber, isPlaying = True).annotate(votesreceived=Count('voteforplayer', filter=Q(playervote__gamephasenumber = activegame.game.phasenumber))).order_by('-votesreceived')
playerswithvotes = Player.objects.select_related('game').filter(game = activegame.game, game__phasenumber = activegame.game.phasenumber, isPlaying = True).annotate(votesreceived=Count('voteforplayer')).filter(playervote__gamephasenumber = activegame.game.phasenumber).order_by('-votesreceived')
解决方案

核心问题是反向关联名称使用错误:Player与PlayerVote的反向关联通过related_name="voteforplayer"定义,所以过滤投票阶段时要使用这个名称,而非playervote。

正确实现代码如下:

current_phase = activegame.game.phasenumber
playerswithvotes = Player.objects.select_related('game')
    .filter(game=activegame.game, isPlaying=True)
    .annotate(
        votesreceived=Count(
            'voteforplayer',
            filter=Q(voteforplayer__gamephasenumber=current_phase)
        )
    )
    .order_by('-votesreceived')

细节说明:

  1. 关联名称修正:用voteforplayer__gamephasenumber替代错误的playervote__gamephasenumber,匹配模型中定义的related_name。
  2. 代码简化:game__phasenumber过滤可以省略,因为game=activegame.game已经锁定目标游戏,其phasenumber就是当前阶段。
  3. 保留所有活跃玩家:不要在annotate后添加阶段过滤,否则会丢失当前阶段未获票的玩家,我们需要保留所有活跃玩家的记录(得票数为0的也会显示)。
  4. 可读性优化:提取current_phase变量,避免重复调用activegame.game.phasenumber,让代码更清晰。

内容的提问来源于stack exchange,提问作者phuefi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:15:34