Django查询中何时添加“_set”?为何关联引用写法不同?
_set的判断方法 核心逻辑:区分正向与反向关联
在Django ORM中,是否需要加_set,完全取决于你是从关联关系的哪一端发起查询:
1. 正向关联(从外键所在模型指向关联模型)
如果查询是从包含ForeignKey字段的模型出发(比如从Tweet查关联的User),直接用外键字段名即可,不需要加_set。因为Tweet里明确定义了user字段,ORM能直接识别这个关联。
2. 反向关联(从被关联模型指向外键所在模型)
如果查询是从被外键关联的模型出发(比如从User查关联的所有Tweet),因为User模型本身没有直接的tweet字段,Django会自动生成一个反向关联管理器,默认命名规则是[关联模型名小写]_set,也就是tweet_set。这时候必须用这个带_set的名称来调用反向关联。
针对你的代码示例拆解
为什么prefetch_related用tweet_set
prefetch_related是在User的查询集上调用的,属于反向关联查询(从User拉取关联的Tweet数据),所以必须使用Django自动生成的反向管理器名称tweet_set。
为什么annotate里用tweet__favorite
annotate中使用的是Django ORM的跨表关联语法,这里的tweet是关联模型Tweet的小写名称。ORM会自动识别这种写法,通过User和Tweet的外键关联关系,去关联查询Tweet表中的favorite字段,不需要手动加_set后缀。
额外优化:自定义反向关联名称
如果你觉得默认的[模型名]_set不够直观,可以在定义外键时通过related_name参数指定自定义名称:
class Tweet(models.Model): user = models.ForeignKey("User", related_name="tweets") favorite = models.IntegerField(default=0)
之后,prefetch_related就可以用"tweets"代替tweet_set,但在annotate的跨表语法里,依然使用tweet__favorite(这里依赖的是模型名小写,而非自定义的related_name)。
内容的提问来源于stack exchange,提问作者y.dai

