Django中如何双向过滤一对多关联关系?
嗨,这问题我熟!咱们先理清楚你这儿的问题出在哪儿:
你给Child模型的外键字段parent设置了related_name="parent_project",这个related_name的作用是让Parent模型可以通过这个名称反向关联到对应的所有Child实例——简单说,parent_project代表的是某个Parent下面的所有Child对象的集合,而不是某个具体字段,所以你直接用parent_project__contains="test"肯定会报错,因为Django不知道你要过滤集合里的哪个字段呀!
正确的写法应该是通过related_name进一步指定要过滤的Child模型的字段,也就是:
Parent.objects.filter(parent_project__name__contains="test")
解释下这个语句的逻辑:
parent_project:找到当前Parent关联的所有Child对象__name:定位到Child模型里的name字段__contains="test":过滤出name字段包含"test"的Child对应的Parent
要是你没设置related_name的话,Django会默认用模型名_set作为反向关联名,那写法就会是Parent.objects.filter(child_set__name__contains="test"),不过你这里已经自定义了related_name,所以用parent_project就对了。
再回头看你之前尝试的Parent.objects.filter(child__name__contains="test"),这个写法不对是因为你没使用自己设置的related_name,Django找不到名为child的反向关联字段,所以也会报错。
总结一下,反向过滤一对多关系的核心就是:反向关联名 + 双下划线 + 子模型的字段名 + 过滤条件,别直接对关联集合用过滤 lookup 就行~
备注:内容来源于stack exchange,提问作者whitebear

