我将如何将这些多个连接作为 Django 查询集进行?
Posted
技术标签:
【中文标题】我将如何将这些多个连接作为 Django 查询集进行?【英文标题】:How would I do these multiple joins as a Django queryset? 【发布时间】:2018-10-07 10:31:04 【问题描述】:我有一个将多个表连接在一起的查询:
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
不是任何表中的外键,我将如何进行第三次连接?谢谢!
【问题讨论】:
【参考方案1】:select_related(*fields) 返回一个将“遵循”外键关系的查询集,[...]
根据 django 文档select_related
遵循外键关系。 player_data
更接近外键,甚至不是Stats
的字段。如果你想INNER join PlayerData
和 Player
你可以按照它的外键。在你的情况下使用
double-underscore 转至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 join(顺便说一句,如果不使用raw 也不是那么容易:Django Custom Left Outer Join)也可以得到照顾。
关于您的模型的快速说明:
-
默认情况下,每个模型都有一个自动递增的主键,可以通过
.id
或.pk
访问。所以不需要添加例如player_id
models.ForeignKey
字段引用了一个对象,而不是它的 id。因此,将player_id
重命名为player
更直观。如果您将字段命名为 player
,django 允许您通过 player_id
自动访问它的 id
【讨论】:
太棒了,谢谢!PlayerData
的双下划线有效。我的第三次加入太糟糕了。至于自动递增的主键,我没有使用它,因为这些表中的数据来自第三方。
很高兴我能帮上一点忙。您仍然可以在创建时手动设置 id,即使它是自动递增的。但是,如果您选择故意重命名它,我认为这没有问题。我只是认为在这种特殊情况下会更加一致。以上是关于我将如何将这些多个连接作为 Django 查询集进行?的主要内容,如果未能解决你的问题,请参考以下文章
Django 查询 - 将用户类与 Telegram Bot 的 OnetoOnefield 类连接起来