如何使用select_related联接多个Django模型 解决外键查询报错问题
核心原因
select_related 仅支持通过 JOIN 语句在单次SQL查询中关联正向外键、正向OneToOne、反向OneToOne关系。你场景中Alpha到XXX属于反向一对多关系(一个Alpha可对应多个XXX实例),这种关系无法通过简单JOIN在不重复主表数据的前提下完成查询,因此Django不支持在select_related中指定反向一对多的关联名。
另外你代码里写的关联名XXX也和Django默认生成的反向访问器名不符:默认情况下访问Alpha关联的XXX实例需要用alpha.xxx_set.all(),如果你要自定义反向名为XXX,需要在外键字段显式指定:
class XXX(models.Model): owner = models.ForeignKey(Alpha, related_name="XXX")
不用prefetch_related的替代方案
如果你的业务逻辑允许调整查询方向,可以直接从XXX侧发起查询,正向关联Alpha即可,全程仅执行单次SQL:
# 正向查询,一次性拿到所有符合条件的XXX及关联的Alpha对象 xxx_list = XXX.objects.filter(owner_id=pk).select_related('owner') # 可从结果中提取对应的Alpha对象 alpha = xxx_list[0].owner if xxx_list else None
这种方式性能和你直接查询Alpha加关联的效率完全一致。
必须从Alpha侧发起查询的处理方案
这种场景下你只能使用prefetch_related,但不需要过度担心性能问题:prefetch_related只会额外发起1次关联表的批量查询,而非N+1查询,对于绝大多数业务场景来说额外1次查询的损耗极低。
你可以把支持select_related的关系(比如YYY)放在select_related中,反向一对多的关系放在prefetch_related中即可:
test = Alpha.objects.filter(id=pk)\ .select_related('YYY')\ .prefetch_related('XXX', '其他需要关联的反向一对多字段')\ .first()
内容的提问来源于stack exchange,提问作者sixovov947
相关产品推荐
相关产品推荐

