Skip to main content
 首页 » 编程设计

python之查询多个 SQLAlchemy 多对多关系

2025年05月04日14duanxz

我正在使用 SQLAlchemy 对以下概念建模:

  • 一个用户可以是一个member_of一个组
  • 一个组可以有多个用户作为成员,并且可以提供access_to多个节点。
  • 一个节点可以accessed_by多个Groups

我正在使用关联表模式为用户 -> 组和节点 -> 组创建多对多关系。

代码如下(我使用的是 Flask-SQLAlchemy,这就是为什么我有 db.Model 等)

如何查询用户所属的所有组可以访问的所有节点?

这是对象模型

group_access = Table('access', db.metadata, 
                     Column('group_id', Integer, ForeignKey('groups.group_id')), 
                     Column('nid', BigInteger, ForeignKey('nodes.nid')), 
                     ) 
 
group_membership = Table('membership', db.metadata, 
                         Column('group_id', Integer, ForeignKey('groups.group_id')), 
                         Column('uid', Integer, ForeignKey('users.id')), 
                         ) 
 
edges = Table('edges', db.metadata, 
              Column('src_id', BigInteger, ForeignKey('nodes.nid'), primary_key=True), 
              Column('dest', BigInteger, ForeignKey('nodes.nid'), primary_key=True), 
              ) 
 
 
class User(db.Model): 
    __tablename__ = 'users' 
 
    id = Column(Integer, primary_key=True) 
    email = Column(String, unique=True, nullable=False) 
    member_of = relationship("Group", secondary=group_membership, back_populates='members') 
 
    def __init__(self, email): 
        self.email = email 
 
 
class Node(db.Model): 
    __tablename__ = 'nodes' 
 
    nid = Column(BigInteger, primary_key=True) 
    type = Column(String) 
    parents = relationship("Node", 
                           secondary=edges, 
                           primaryjoin="Node.nid==edges.c.src_id", 
                           secondaryjoin="Node.nid==edges.c.dest", 
                           backref="children") 
    accessed_by = relationship("Group", secondary=group_access, back_populates='access_to') 
 
    def __init__(self, owner=None, type=None): 
        self.type = type 
        # self.owner = owner 
 
    def __repr__(self): 
        return "<{} nid:{} >".format(self.type, self.nid) 
 
 
class Group(db.Model): 
    __tablename__ = 'groups' 
 
    group_id = Column(Integer, primary_key=True) 
    type = Column(String) 
    members = relationship("User", secondary=group_membership, back_populates="member_of") 
    access_to = relationship("Node", secondary=group_access, back_populates="accessed_by") 
 
    def __init__(self, name): 
        self.type = name 
 
    def __repr__(self): 
        return self.type 

请您参考如下方法:

可以使用连接形成获取与给定用户相关的节点的查询:

db.session.query(Node).\ 
    join(Node.accessed_by).\ 
    join(Group.members).\ 
    filter(User.id == u.id).\ 
    all() 

由于 SQLAlchemy 处理模型实体的方式,重复行不是问题。您还可以使用 EXISTS,它不会产生重复项:

db.session.query(Node).\ 
    filter(Node.accessed_by.any( 
        Group.members.any(User.id == u.id))).\ 
    all()