简体   繁体   中英

SQLAlchemy join with association tables

In a Flask app that uses SQLAlchemy, I have tables for users and assets. The users belong to zero to multiple groups, and the access to each asset is allowed to zero to several of these groups. These relationships are modeled with association tables (the basic structure is shown below). I can query the database and the association tables work as intended.

The part where I am struggling is to, given a user, retrieve the assets that this user is allowed to access. I understand that I need to join on groups.

In SQL, the following statement gives the result that I need:

select * from user as u 
  join association_user_group as aug on u.id == aug.user_id 
  join association_asset_group as aag on aag.group_id = aug.group_id
  where username='some_name'; 

However, I can't figure out how to translate this to Flask-SQLAlchemy, leveraging its benefits (which I like in many contexts).

For simplicity, let's assume the user under consideration is User.query.first() (in my code I have a reference to this object).

The basic database definition is as follows:

association_user_group = db.Table(
    'association_user_group',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('group_id', db.Integer, db.ForeignKey('group.id'))
)

association_asset_group = db.Table(
    'association_asset_group',
    db.Column('asset_id', db.Integer, db.ForeignKey('asset.id')),
    db.Column('group_id', db.Integer, db.ForeignKey('group.id'))
)

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    ...

class Asset(db.Model):
    __tablename__ = 'asset'
    id = db.Column(db.Integer, primary_key=True)
    ...

class Group(db.Model):
    __tablename__ = 'group'
    id = db.Column(db.Integer, primary_key=True)
    ...

    users = db.relationship(
        'User',
        secondary=association_user_group,
        backref=db.backref('groups', lazy='dynamic'))
    asset = db.relationship(
        'Asset',
        secondary=association_asset_group,
        backref=db.backref('groups', lazy='dynamic'))

Update : In the meanwhile, the following kind of works, but it does not make use of the db.relationship s defined in the classes, which seems like a shame:

db.session.query(association_asset_group) \
          .join(association_user_group,
                association_user_group.c.group_id
                == association_asset_group.c.group_id) \
          .filter(association_user_group.c.user_id == u.id)

This seems to do the job:

q = db.session.query(Asset) \
              .join(Group, User.groups) \
              .join(Asset, Group.assets) \
              .filter(User.id == u.id) \
              .distinct() 

But I have to say that I find it difficult to grasp the glue that flask-sqlalchemy provides under the hood (and when not).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM