You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

运行逻辑:

  1. 先取self.relationships拿到所有当前用户主动发起关系指向的用户集合
  2. 第一个过滤条件to_people__status=status:跨表查询这些用户作为接收方的中间表记录,筛选出状态等于传入参数的记录
  3. 第二个过滤条件to_people__from_person=self:确保这些中间表记录的发起方就是当前用户,避免匹配到其他用户发起的无关关系

返回结果:当前用户主动发起的、状态为指定值的所有关联用户。比如传RELATIONSHIP_FOLLOWING返回当前用户关注的所有人,传RELATIONSHIP_BLOCKED返回当前用户拉黑的所有人。

def get_related_to(self, status):
    return self.related_to.filter(
        from_people__status=status,
        from_people__to_person=self)

运行逻辑:

  1. 先取self.related_to拿到所有主动发起关系指向当前用户的用户集合
  2. 第一个过滤条件from_people__status=status:跨表查询这些用户作为发起方的中间表记录,筛选出状态等于传入参数的记录
  3. 第二个过滤条件from_people__to_person=self:确保这些中间表记录的接收方就是当前用户,排除指向其他用户的无关关系

返回结果:其他用户主动发起的、指向当前用户、状态为指定值的关联用户。比如传RELATIONSHIP_FOLLOWING返回当前用户的所有粉丝,传RELATIONSHIP_BLOCKED返回所有拉黑了当前用户的人。

filter与反向查询配合的核心规则

Django的ORM跨表查询遵循以下规则:

  • 双下划线__用于跨关联关系查询对应表的字段,正向反向都适用
  • 反向查询默认使用小写的关联模型名,如果你给外键或者多对多字段设置了related_name,就用你设置的related_name替代模型名做反向查询
    这两个方法的核心就是先拿到初步的关联用户集合,再通过中间表的反向关系做二次筛选,确保返回的结果只包含和当前用户相关的、符合状态要求的用户。

内容的提问来源于stack exchange,提问作者Atharva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 13:36:02