Flask-SQLAlchemy: Multilevel Relationships
- From:
- Christoph Erdle
- Date:
- 2011-07-27 @ 17:29
Hi,
I'm trying to implement an in my view simple authorization scheme: users
and groups get access to environments, the access can be granted on user
and on group level, users can be members of groups. So far I implemented
the following models and mappingtables using Flask-SQLAlchemy. Is there a
way to "chain" the relationships, e.g. query the user's groups'
environments? I thought about something like
current_user().groups.environments (current_user() gets me the currently
logged in user object user certificate based authentication), but then i
get back the error:
AttributeError: 'InstrumentedList' object has no attribute 'environments'
Getting the user's groups works perfectly, also getting a user's
environments and a group's environment. What's missing is the part, where
I get the environments the user is "inheriting" through his group
memberships. Likely I'm missing some kind of "magic" to link the models
together with (Flask-)SQLAlchemy, or is this only possible using direct
SQL queries joining the relevant tables together circumventing the ORM?
Any input is highly appreciated.
Kind regards,
Chris
Model definition:
------
class Environment(db.Model):
__tablename__ = 'environment'
id = db.Column(db.Integer, primary_key=True)
fs_rel_path = db.Column(db.String, nullable=False)
active = db.Column(db.Boolean, nullable=False)
display_name = db.Column(db.String, nullable=False)
users = db.relationship('User', secondary=userenvironmentmapping,
backref=db.backref('environments', lazy='joined'), lazy='joined')
groups = db.relationship('Group', secondary=groupenvironmentmapping,
backref=db.backref('environments', lazy='joined'), lazy='joined')
def __init__(self, fs_rel_path=None, display_name=None, active=True):
self.fs_rel_path = fs_rel_path
self.display_name = display_name
self.active = active
def __repr__(self):
return self.display_name
class Group(db.Model):
__tablename__ = 'group'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
admin = db.Column(db.Boolean, nullable=False)
#members = db.relationship('User', secondary=usergroupmembership,
backref='groups', lazy='dynamic')
def __init__(self, name=None, admin=False):
self.name = name
self.admin = admin
def __repr__(self):
return self.name
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
cert_dn = db.Column(db.String, nullable=False, index=True)
admin = db.Column(db.Boolean, nullable=False)
groups = db.relationship('Group', secondary=usergroupmembership,
backref=db.backref('users', lazy='joined'), lazy='joined')
def __init__(self, cert_dn=None, admin=False):
self.cert_dn = cert_dn
self.admin = admin
def __repr__(self):
return self.cert_dn
usergroupmembership = db.Table('user_group_membership',
db.Column('id', db.Integer, primary_key=True),
db.Column('user_id', db.Integer, db.ForeignKey('user.id',
onupdate="CASCADE", ondelete="CASCADE"), index=True),
db.Column('group_id', db.Integer, db.ForeignKey('group.id',
onupdate="CASCADE", ondelete="CASCADE"), index=True)
)
userenvironmentmapping = db.Table('user_environment_mapping',
db.Column('id', db.Integer, primary_key=True),
db.Column('user_id', db.Integer, db.ForeignKey('user.id',
onupdate="CASCADE", ondelete="CASCADE"), index=True),
db.Column('environment_id', db.Integer,
db.ForeignKey('environment.id', onupdate="CASCADE", ondelete="CASCADE"),
index=True)
)
groupenvironmentmapping = db.Table('group_environment_mapping',
db.Column('id', db.Integer, primary_key=True),
db.Column('group_id', db.Integer, db.ForeignKey('group.id',
onupdate="CASCADE", ondelete="CASCADE"), index=True),
db.Column('environment_id', db.Integer,
db.ForeignKey('environment.id', onupdate="CASCADE", ondelete="CASCADE"),
index=True)
)