簡體   English   中英

在SQLAlchemy中查詢多對多

[英]Query many-to-many in SQLAlchemy

我有以下型號。 用戶具有多個角色,並且一個角色可以具有許多權限。 我不太明白如何查詢以獲得想要的東西。

user_role = db.Table(
    'user_role',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
    db.UniqueConstraint('user_id', 'role_id')
)

role_permission = db.Table(
    'role_permission', 
    db.Column('permission_id', db.Integer, db.ForeignKey('permission.id')),
    db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
    db.UniqueConstraint('permission_id', 'role_id')
)

class Role(Base):
    __tablename__ = 'role'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False)

class Permission(Base):
    __tablename__ = 'permission'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)

    roles = db.relation(Role, secondary=role_permission, backref=db.backref('permissions'))

class User(Base, UserMixin):
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(60), unique=True, nullable=False)
    password_hash = db.Column(db.String(80), nullable=False)

    roles = db.relation(Role, secondary=user_role, backref=db.backref('users'))

我想獲得分配給用戶的所有權限的列表(最好是唯一的),但是我似乎無法弄清楚該如何做。

我可以通過在User模型中創建一個生成器來獲取列表:

def get_all_permissions(self):
    for role in self.roles:
        for perm in role.permissions:
            yield perm

但我很希望能夠在一個查詢中做到這一點。

好吧,僅獲取權限列表,請嘗試如下操作:

permissions = session.query(Permission).\
    join(Role).join(User).filter(User.username='MisterX').all()

或過濾您想要的任何東西。 要使權限唯一,可以使用group by:

permissions = session.query(Permission.id, Permission.name).join(Role).join(User).\
    filter(User.username='MisterX').group_by(Permission.id).all()

或者,如果沒有特殊查詢,則可以使用聲明性擴展:

permissions = User.roles.permissions

有幫助嗎?

您未指定元數據參數,可能無法正確識別關聯表。 該腳本對我有用:

#!/bin/python

from sqlalchemy import Table
from sqlalchemy import Integer, String, ForeignKey, create_engine, Column, PrimaryKeyConstraint
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()

user_role = Table(
    'user_role',
    Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id')),
    Column('role_id', Integer, ForeignKey('roles.id')),
    PrimaryKeyConstraint('user_id', 'role_id')
)

role_permission = Table(
    'role_permission', 
    Base.metadata,
    Column('permission_id', Integer, ForeignKey('permissions.id')),
    Column('role_id', Integer, ForeignKey('roles.id')),
    PrimaryKeyConstraint('permission_id', 'role_id')
)

class Role(Base):
    __tablename__ = 'roles'

    id = Column(Integer, primary_key=True)
    name = Column(String(100), unique=True, nullable=False)

class Permission(Base):
    __tablename__ = 'permissions'

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

    roles = relationship("Role", secondary=role_permission, backref=backref('permissions'))

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    username = Column(String(60), unique=True, nullable=False)
    password_hash = Column(String(80), nullable=False)

    roles = relationship("Role", secondary=user_role, backref=backref('users'))


Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()

u = User(username="user", password_hash="secret")

r1 = Role(name="Role 1")
session.add(r1)
r2 = Role(name="Role 2")
session.add(r2)

p1 = Permission(name="Permission 1")
p2 = Permission(name="Permission 2")
p3 = Permission(name="Permission 3")

r1.permissions.append(p1)
r1.permissions.append(p2)

r2.permissions.append(p2)
r2.permissions.append(p3)


u.roles.append(r1)
u.roles.append(r2)

session.add(u)

for perm in session.query(Permission).join(Role, Permission.roles).\
    join(User, Role.users).filter(User.username=="user").distict()all():
    print(perm.name)

如果您已經將User對象以及Permissions和Roles一起加載到內存中,則您的代碼應快速完成操作,而無需進入數據庫。

否則,此查詢應工作:

    user_id = 789
    permissions = (db.session.query(Permission)
            .join(Role, Permission.roles)
            .join(User, Role.users)
            .filter(User.id == user_id)
            ).distinct()
    #print(permissions)
    for perm in permissions:
        print(perm)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM