django 如何根据中介表中的字段对多对多关系排序?

0aydgbwb  于 2023-08-08  发布在  Go
关注(0)|答案(1)|浏览(101)

我正在编写一个Django应用程序,用于跟踪视频游戏中玩家的排名统计数据。
当我定义多对多关系的“through”字段时,我希望使用中间对象的“ordering”Meta字段对结果查询进行排序。
我无法通过下面的测试。我的DB完全迁移了。我哪里误会了?
型号代码

from django.db import models

class Player(models.Model):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, unique=True, editable=False)
    name = models.CharField(max_length=255)

class GameMode(models.Model):
    name = models.CharField(max_length=30)
    leaderboard = models.ManyToManyField(Player, through="ELO", related_name="game_modes")

class ELO(models.Model):
    player = models.ForeignKey(Player, related_name="elos", on_delete=models.PROTECT)
    game_mode = models.ForeignKey(GameMode, related_name="elos", on_delete=models.PROTECT)
    current = models.PositiveIntegerField(default=0)
    peak = models.PositiveIntegerField(default=0)

    class Meta:
        unique_together = ["player", "game_mode"]
        ordering = ("-current",)

字符串
测试代码

def test_leaderboard_works_okay_with_different_game_modes(db):
    # checks that creating player elos will have them sorted on the game_mode leaderboard
    game_mode1 = GameMode.objects.create()
    game_mode2 = GameMode.objects.create()
    player1 = Player.objects.create()
    player2 = Player.objects.create()

    ELO.objects.create(game_mode=game_mode1, player=player1, current=1500)
    ELO.objects.create(game_mode=game_mode2, player=player1, current=1000)

    ELO.objects.create(game_mode=game_mode1, player=player2, current=1000)
    ELO.objects.create(game_mode=game_mode2, player=player2, current=1500)

    assert game_mode1.leaderboard.first() == player1
    assert game_mode2.leaderboard.first() == player2


错误日志
排行榜上有玩家列表,但他们的排序不正确,Assert失败。

>       assert game_mode2.leaderboard.first() == player2
assert <Player: Player object (30a9670a-28de-4027-b7c0-70cec65ec08e)> == <Player: Player object (829acf41-03fd-45ef-b1eb-3b3f7c7170a0)>
E        +  where <Player: Player object (30a9670a-28de-4027-b7c0-70cec65ec08e)> = <bound method QuerySet.first of <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f63abb5b890>>()
E        +    where <bound method QuerySet.first of <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f63abb5b890>> = <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f63abb5b890>.first
E        +      where <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f63abb5b890> = <GameMode: GameMode object (58)>.leaderboard

ngynwnxp

ngynwnxp1#

我找到了更好的解决办法。最好把玩家属性称为它是什么(一组玩家),并定义一个排行榜属性来排序他们。我可以使用相关名称“elos__current”在上下文中获取当前ELO。
这个改变通过了我的测试。

class GameMode(models.Model):
    name = models.CharField(max_length=30)
    players = models.ManyToManyField("players.Player", through="ELO", related_name="game_modes")

    @property
    def leaderboard(self):
        return self.players.order_by("-elos__current")

字符串

相关问题