On Jan 21, 2013, at 8:41 AM, Damian Dimmich wrote:

> Hi
> 
> I have an application that was originally written to support just one 
> organisation.  This app is now being modified to support multiple 
> organisations.  As such I am trying to update the main bits of the model to 
> always filter queries by organisation_id, a new column I have added in to the 
> relevant tables.
> 
> For example, a class Users, used for authentication would have (so the 
> login/logout/reset password functions would be modified to use this):
> 
> class AllUser(Base):
>    __tablename__ = 'users'
>    id = sa.Column(sa.Integer, primary_key=True)
>    username = sa.Column(sa.Unicode(15), nullable=False, unique=True)
>    organisation_id = sa.Column(sa.Integer, sa.ForeignKey('organisation.id'))
>    organisation = sa.orm.relationship('Organisation')
> 
> 
> and the 'restricted' version would just show users from the organisation (all 
> other existing parts of the application would use this class for its queries) 
> :
> 
> class User(Base):
>    __table__ = 
> select([users_table]).where(users_table.c.organisation_id==session['organisation_id'])
>    id = sa.Column(sa.Integer, primary_key=True)
>    username = sa.Column(sa.Unicode(15), nullable=False, unique=True)
>    organisation_id = sa.Column(sa.Integer, sa.ForeignKey('organisation.id'))
>    organisation = sa.orm.relationship('Organisation')
> 
> where session['organisation_id'] is the organisation id of the currently 
> logged in user.
> 
> Is this a sensible approach?  Are there any concurrency issues I should be 
> aware of such as: would the __table__ select statement be cached/reused from 
> one request to the next?

well yeah that actually wouldn't work at all, __table__ = select()... is 
evaluated immediately, so whatever is in "session['org_id']" at that point is 
baked into the query.

You can make it work if you use a callable there ("callable_" with bindparam() 
is SQLAlchemy 0.8):

        __table__ = select(...).where(table.c.org_id == bindparam(None, 
callable_=lambda: session['organization_id']))

but why is it important that the query here be broken up at the class level ?   
The only time the difference between AllUser and User has any significance is 
when you say:

        query(AllUser)  / query(User)

why is that better than just saying:

        query(User) / query(User).filter(User.with_session_organization)

?   (an expression like "User.with_session_organization" can be created using a 
hybrid attribute: 
http://docs.sqlalchemy.org/en/rel_0_8/orm/extensions/hybrid.html)

unless it's your aim to create a relationship() that refers to User.  In which 
case you can also add that bindparam() idea to the "primaryjoin" condition of 
relationship.  An example that uses this technique is here: 
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/GlobalFilter  though if you 
had a callable_ inside the bindparam(), you wouldn't need the "options" used in 
that example.


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to