首页 > 解决方案 > 我将如何将这些多个连接作为 Django 查询集进行?

问题描述

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

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'。选择是:玩家

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

标签: pythondjangopython-3.xdjango-modelsdjango-queryset

解决方案


select_related(*fields)返回将“遵循”外键关系的 QuerySet,[...]

根据 django 文档, select_related遵循外键关系。player_data更接近外键,甚至不是Stats. 如果你想INNER 加入 PlayerDataPlayer你可以按照它的外键。在您的情况下,使用 双下划线到达PlayerData

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。因此,将 example 重命名player_idplayer. 如果你命名你的字段playerdjango 允许你自动访问它的 id 通过player_id

推荐阅读