如何一次查询多个表?

时间:2013-11-21 14:27:11

标签: python sql django

我有什么

我有一个应用程序,可以在国际象棋游戏中存档比赛。该应用程序包括以下模型:

class Tournament(models.Model):
    name = models.CharField(max_length=128)

class Player(models.Model):
    name = models.CharField(max_length=128)

# Abstract base class
class Match(models.Model):
    tournament = models.ForeignKey(Tournament)
    playerA = models.ForeignKey(Player, related_name='%(class)s_A') # eg. mastertournament_A
    playerB = models.ForeignKey(Player, related_name='%(class)s_B')
    score = models.CharField(max_length=16)

    class Meta:
        abstract = True 

# here are tables of ``Match`` instances played out in a particular 
# tournaments. All ``Match`` instances share the same fields 
# so, I could also have one big table for all matches but I want to keep 
# each Tournament in separate table for easiness.
class MasterTournament(Match):
    pass  

class AmateurTournament(Match):
    pass

现在,我计划有两种不同的观点:tournament_view(列出锦标赛中所有比赛)和player_view(列出所有比赛中玩家所有比赛)

要解决的问题

鉴于我提到的观点,我需要为每个观点执行两个不同的查询。 在tournament_view我将有过滤器(选择过滤器)playerAplayerB,我需要为它们动态填充选项。这可以通过以下方式轻松完成:

playersA_all = MasterTournament.objects.value_list('playerA')
playersB_all = MasterTournament.objects.value_list('playerB')

但是,我正在努力想出player_view的查询。此视图与选择过滤器playerAplayerB非常相似,但现在,我需要查询所有锦标赛表格以获取正在查看的玩家的所有对手。这将导致每次都有一堆数据库命中,在这个过程中我需要引入一个临时列表来保存和追加来自不同表的结果。

这就是为什么我觉得我需要重新组织我的模型,但是我想到的唯一解决方案是将所有锦标赛的比赛包装在一起,这是我希望防止发生的事情。

我的问题是,您对如何调整我的模型有任何想法,或者django确实提供了执行player_view所需查询的解决方案吗?

3 个答案:

答案 0 :(得分:2)

我之前实际上做过类似的事情,虽然我没有使用Django来做这件事。当比赛数量变大时,获得所有对手的概念就成了问题。我能够利用我的解决方案来跟踪输赢,而无需动态计算。

请访问www.eurosportscoreboard.com。

无论如何,我解决它的方式是使用触发器。您可以使用保存信号执行相同的操作。

创建与OpponentPlayer具有fk关系的Match模型。保存Match后,为每位玩家创建Opponent。写入会有点慢,但读取速度会非常快。

答案 1 :(得分:1)

不要有两个ForeignKey字段,而是有一个ManyToMany字段:

class Match(models.Model):
    tournament = models.ForeignKey(Tournament)
    players = models.ManyToManyField(Player, through='Participate')
    score = models.CharField(max_length=16)

class Participate(models.Model):
    player = models.ForeignKey(Player)
    match = models.ForeignKey(Match)
    visitor = models.BooleanField()

我认为它解决了你的大多数问题,也更有意义,因为没有必要将A定义为A而B是B.这两个都是玩家,它们之间没有什么特别的区别。

答案 2 :(得分:0)

您无法一次查询多个表格!您可以进行多次查询和联合结果。

# so, I could also have one big table for all matches but I want to keep 
# each Tournament in separate table for easiness.

如果您需要查询结果中两个表的信息,这是一个错误的决定。考虑如何查询(使用2个表)一个tournamet匹配或正分数匹配或与特定玩家匹配 - 您必须对2个表和联合结果进行查询,使DB负载加倍。在这种情况下,你应该为匹配创建一个表,我想,并为匹配类型创建一个字段 - Master或Amauter:

class Match(models.Model):
    tournament = models.ForeignKey(Tournament)
    playerA = models.ForeignKey(Player, related_name='%(class)s_A') # eg. mastertournament_A
    playerB = models.ForeignKey(Player, related_name='%(class)s_B')
    score = models.CharField(max_length=16)
    master_or_amauter = models.BooleanField(default=True) # master by default

使用一张桌子,你在player_view中没有问题......