通过SqlAlchemy中的M2M关系与“跳转”的关系(用户->角色->权限)

时间:2019-05-06 03:03:37

标签: python sqlalchemy relationship m2m

我正在尝试建立一个非常典型的权限结构模型,其中可以将User模型(我网站的人类用户)分配给某些Roles,而每个Roles都有一些Permissions

如果我能直接从relationshipUser得到一个Permission,那将真的很有帮助。这样,我可以从数据库中获取一个 user (实例),然后执行user.permissions来获得他的权限,进行一些过滤以检查用户是否具有特定的Permission ,将它们预先加载...总而言之:relationship附带的所有好东西。

viewonly关系将是完美的。正如Mike Bayer在a very similar question中提到的那样,我无法写到User.permissions,因为我们不知道要使用哪个'Role'或在 中插入它。

我创建了两个中间表:

User -- M2M --> Role(s) -- M2M --> Permission(s)
 |                                     ^
 +-------- user.permissions -----------+
  • users_roles通过其主键(ID)将user连接到其roles
  • roles_permissions将每个role连接到其permissions

这是我的表结构(简化了问题,但即使是完整版也很典型,而且...简单)

class User(DeclarativeBase, Mixin):
    __tablename__ = 'users'
    email = Column(String(25), nullable=False)

_users_roles = Table('users_roles', DeclarativeBase.metadata,
    Column('user_id', ForeignKey('users.id', ...
    Column('role_id', ForeignKey('roles.id', ...
    PrimaryKeyConstraint('user_id', 'role_id',),
)    

class Role(DeclarativeBase, Mixin):
    __tablename__ = 'roles'

    name = Column(Text(), nullable=False, unique=True)
    users = relationship("User", secondary=_users_roles, backref="roles")

_roles_permissions = Table('roles_permissions', DeclarativeBase.metadata,
    Column('role_id', ForeignKey('roles.id',  ...
    Column('permission_id', ForeignKey('permissions.id', ...
    PrimaryKeyConstraint('role_id', 'permission_id',),
)

class Permission(DeclarativeBase, Mixin):
    __tablename__ = 'permissions'

    key = Column(Text, nullable=False, unique=True,) 

我看到this other answer看起来非常有前途,但是我似乎无法使其工作。老实说,我一直在尝试很多组合,我想说我最想知道的就是这个:

permissions = relationship('Permission',
    secondary="""join(User, users_roles, 
                     User.id == users_roles.c.user_id
                 ).join(roles_permissions, 
                    users_roles.c.role_id == roles_permissions.c.role_id
                ).join(
                  Permission, roles_permissions.c.permission_id == Permission.id
               )""",
    viewonly=True,
)

哪个给我这个错误:

sqlalchemy.exc.ArgumentError: Relationship User.permissions 
could not determine any unambiguous local/remote column pairs 
based on join condition and remote_side arguments.  Consider 
using the remote() annotation to accurately mark those elements
of the join condition that are on the remote side of the relationship.

任何提示将不胜感激。预先谢谢你。

1 个答案:

答案 0 :(得分:2)

辅助表不应包括相关表本身,而应包括它们之间的关联:

permissions = relationship(
    'Permission',
    secondary="""join(users_roles, roles_permissions, 
                      users_roles.c.role_id == roles_permissions.c.role_id)""",
    viewonly=True,
)

在辅助数据库中具有要联接的表会使试图通过辅助数据库查找UserPermission之间的外键关系的自动化感到困惑。