我如何将这些多个连接作为Django查询集进行?

时间:2018-04-26 16:21:52

标签: python django python-3.x django-models django-queryset

我有这个将多个表连接在一起的查询:

select 
    p.player_id
    , d.player_data_1
    , l.year
    , l.league
    , s.stat_1
    , l.stat_1_league_average
from 
    stats s
inner join players p on p.player_id = s.player_id
left join player_data d on d.other_player_id = p.other_player_id
left join league_averages as l on l.year = s.year and l.league = s.year
where 
    p.player_id = 123

我的模特看起来像这样:

class Stats(models.Model):
    player_id = models.ForeignKey(Player)
    stat_1 = models.IntegerField()
    year = models.IntegerField()
    league = models.IntegerField()


class Player(models.Model):
    player_id = models.IntegerField(primary_key=True)
    other_player_id = models.ForeignKey(PlayerData)

class PlayerData(models.Model):
    other_player_id = models.IntegerField(primary_key=True)
    player_data_1 = models.TextField()

class LeagueAverages(models.Model):
    year = models.IntegerField()
    league = models.IntegerField()
    stat_1_league_average = models.DecimalField()

我可以这样做:

Stats.objects.filter(player_id=123).select_related('player')

进行第一次加入。对于第二次加入,我尝试了:

Stats.objects.filter(player_id=123).select_related('player').select_related('player_data')

但是我收到了这个错误:

  

django.core.exceptions.FieldError:select_related:'player_data'中给出的无效字段名称。选择是:玩家

考虑到yearleague不是任何表中的外键,我将如何进行第三次连接?谢谢!

1 个答案:

答案 0 :(得分:0)

  

select_related(*fields)返回一个“跟随”外键关系的QuerySet,[...]

根据django文档select_related遵循外键关系。 player_data是一个外键,甚至是Stats的字段。如果您想要 INNER加入 PlayerDataPlayer,您可以关注其外键。在你的情况下使用 double-underscorePlayerData

Stats.objects.all()
    .select_related('player_id')
    .select_related('player_id__other_player_id')

至于加入LeagueAverages:没有合适的外键,没有办法加入模型,但是使用原始的sql。查看相关问题:Django JOIN query without foreign key。通过使用.raw(),您的 LEFT加入(顺便说一句,如果不使用raw:Django Custom Left Outer Join也不是那么容易)也可以使用。

有关模特的快速说明:

  1. 默认情况下,每个模型都有一个自动递增的主键,可以通过.id.pk访问。因此,无需添加例如player_id
  2. models.ForeignKey字段引用一个对象,而不是它的id。因此,将player_id重命名为player更为直观。如果您为自己的字段命名player,则django允许您通过player_id
  3. 自动访问该字段的ID