Django中Self-referencing many-to-many关系及过滤逻辑疑问
Django自引用多对多关系逻辑解析
前置基础说明
- 这套模型的使用场景是实现用户之间的关注、拉黑双向关系,
symmetrical=False是因为我关注你不代表你关注我,关系是非对称的。 - 先明确几个反向关系的含义:
Person.relationships:正向关系,代表当前用户作为发起方,主动关联的所有用户Person.related_to:是relationships字段的反向关系,代表所有作为发起方、主动关联当前用户的其他用户Relationship.from_person的反向名from_people:代表以某个用户作为关系发起方的所有Relationship中间表记录Relationship.to_person的反向名to_people:代表以某个用户作为关系接收方的所有Relationship中间表记录
两个方法逐行解析
get_relationships 方法
def get_relationships(self, status): return self.relationships.filter( to_people__status=status, to_people__from_person=self)
运行逻辑:
- 先取
self.relationships拿到所有当前用户主动发起关系指向的用户集合 - 第一个过滤条件
to_people__status=status:跨表查询这些用户作为接收方的中间表记录,筛选出状态等于传入参数的记录 - 第二个过滤条件
to_people__from_person=self:确保这些中间表记录的发起方就是当前用户,避免匹配到其他用户发起的无关关系
返回结果:当前用户主动发起的、状态为指定值的所有关联用户。比如传RELATIONSHIP_FOLLOWING返回当前用户关注的所有人,传RELATIONSHIP_BLOCKED返回当前用户拉黑的所有人。
get_related_to 方法
def get_related_to(self, status): return self.related_to.filter( from_people__status=status, from_people__to_person=self)
运行逻辑:
- 先取
self.related_to拿到所有主动发起关系指向当前用户的用户集合 - 第一个过滤条件
from_people__status=status:跨表查询这些用户作为发起方的中间表记录,筛选出状态等于传入参数的记录 - 第二个过滤条件
from_people__to_person=self:确保这些中间表记录的接收方就是当前用户,排除指向其他用户的无关关系
返回结果:其他用户主动发起的、指向当前用户、状态为指定值的关联用户。比如传RELATIONSHIP_FOLLOWING返回当前用户的所有粉丝,传RELATIONSHIP_BLOCKED返回所有拉黑了当前用户的人。
filter与反向查询配合的核心规则
Django的ORM跨表查询遵循以下规则:
- 双下划线
__用于跨关联关系查询对应表的字段,正向反向都适用 - 反向查询默认使用小写的关联模型名,如果你给外键或者多对多字段设置了
related_name,就用你设置的related_name替代模型名做反向查询
这两个方法的核心就是先拿到初步的关联用户集合,再通过中间表的反向关系做二次筛选,确保返回的结果只包含和当前用户相关的、符合状态要求的用户。
内容的提问来源于stack exchange,提问作者Atharva
相关产品推荐
相关产品推荐

