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

Di *_*Zou 1 python django django-models django-queryset python-3.x

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

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
Run Code Online (Sandbox Code Playgroud)

我的模型看起来像这样:

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()
Run Code Online (Sandbox Code Playgroud)

我可以做这样的事情:

Stats.objects.filter(player_id=123).select_related('player')
Run Code Online (Sandbox Code Playgroud)

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

Stats.objects.filter(player_id=123).select_related('player').select_related('player_data')
Run Code Online (Sandbox Code Playgroud)

但我得到了这个错误:

django.core.exceptions.FieldError:select_lated 中给出的字段名称无效:“player_data”。选项有: 玩家

year考虑到这一点并且league任何表中都没有外键,我将如何进行第三次连接?谢谢!

har*_*0ke 6

\n

select_lated(*fields)返回一个 QuerySet,它将 \xe2\x80\x9cfollow\xe2\x80\x9d 外键关系,[...]

\n
\n\n

根据 django 文档, select_related遵循外键关系。player_data既不是外键,也不是 的字段Stats。如果你想要INNER join PlayerDataPlayer你可以遵循它的外键。在您的情况下,使用 \n双下划线来访问PlayerData

\n\n
Stats.objects.all()\n    .select_related(\'player_id\')\n    .select_related(\'player_id__other_player_id\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

至于连接LeagueAverages:没有适当的外键来连接模型,而是使用原始sql。看一下相关问题:Django JOIN query withoutforeign key。通过使用.raw(),您的LEFT 连接(顺便说一下,如果不使用 raw:Django Custom Left Outer Join也不是那么容易)也可以得到处理。

\n\n

关于您的模型的快速说明:

\n\n
    \n
  1. 默认情况下,每个模型都有一个自动递增的主键,可以通过.id或访问.pk。所以不需要添加例如player_id
  2. \n
  3. 字段models.ForeignKey引用一个对象而不是它的 id。因此,重命名为更player_id直观player。如果你命名你的字段,playerdjango 允许你通过以下方式自动访问它的 idplayer_id
  4. \n
\n