Ah right OK that make sense. I was going to say that using undefer felt kind of odd given that there's no existing property so this makes much more sense.
Unfortunately I need to find a solution that works in the mean time until your patch is merged so whilst i have you maybe you can explain why my approach with bind params doesn't work (leveraging the approach in the post Simon) @declared_attr def is_user_default(cls): tbl = UserDefaultDashboard.__table__ user_default_stmt = select([tbl.c.id]).where( tbl.c.id == cls.id ).where( tbl.c.user_id == bindparam('request_user_id', lambda user_id: user_id or cls.user_id) ) return orm.column_property(exists(user_default_stmt), deferred=True) I've got a declared_attr setup. Querying for this works exactly as i expect using `.params(request_user_id=user.id)` however, Creating a new instance of Dashboard and then accessing it's properties will cause this attr to be invoked with the bindparam being passed the lambda function directly. At first i thought i could solve this by deferring the column_property but it seems whenever *any* property on the model is called is_user_default will be called as well?? Here's the query @classmethod def get_user_dashboards(cls, user): stmt = db.session.query(cls).join( Person, Person.id == cls.user_id, ).join( Company, Company.id == Person.company_id, ).filter( or_( cls.user_id == user.id, and_( cls.shared_with_company == true(), Company.id == user.company.id ), cls.shared_with.any(Person.id.in_([user.id])) ), cls.is_deleted == false() ).params( request_user_id=user.id ).options( orm.undefer('is_user_default') ) return stmt Any point doing the following will raise a ProgammingError obj = Dashboard(**params) session.add(obj) session.commit() # now accessing an attribute on obj obj.user_id ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'function' [SQL: 'SELECT EXISTS (SELECT user_default_dashboard.id \nFROM user_default_dashboard \nWHERE user_default_dashboard.id = dashboard.id AND user_default_dashb oard.user_id = %(request_user_id)s) AS anon_1, dashboard.is_deleted AS dashboard_is_deleted, dashboard.name AS dashboard_name, dashboard.description AS dashboard_description, dashboard.user_id AS dashboard_user_id, dashboard.shared_with_c ompany AS dashboard_shared_with_company, dashboard.id AS dashboard_id, dashboard.created_at AS dashboard_created_at, dashboard.updated_at AS dashboard_updated_at \nFROM dashboard \nWHERE dashboard.id = %(param_1)s'] [parameters: {'param_1 ': 'fYW49zSa52J7cZcszR6A9V', 'request_user_id': <function <lambda> at 0x7f72d7a451b8>}] On Thursday, 15 June 2017 18:22:16 UTC+1, Mike Bayer wrote: > > > > On 06/15/2017 11:09 AM, 'mike waites' via sqlalchemy wrote: > > Thanks Mike. > > > > I will definitely give this patch a try. I think this is exactly what > > we need. Simon, thanks so much for sharing that post as well, bindparam > > had completely escaped my attention and that will actually solve my > > immediate use case. > > > > @mike was just wondering if you could clarify something in your proposed > > update on 1.2 that you linked. > > > > | > > a1 =s.query(A).options(undefer(A.x,expression=literal(17))).first() > > | > > > > To me what this is doing is setting the property x on the Model A with > > the result of expression. So given a case where we have a scalar sub > > query it might take the form of.. > > > > | > > a1 > > > =s.query(Dashboard).options(undefer(Dashboard.is_user_default,expression=user_default_subquery).first() > > > > | > > > > Where is_user_default is not defined on the Dashboard Model currently > > but will be set once the query is evaluated with the result of whatever > > is set to expression? > > The plan is that Dashboard will have an attribute is_user_default at all > times, that normally would just return None unless the query sets it to > have some value. The undefer() use above will be refined with a new > function with_expression() that is more specific to this setup. > > There's not an option for the attribute to be added to the Dashboard > object *dynamically*, that is, "Dashboard.is_user_default" needs to be a > known name up front. > > > > > > > > On Thursday, 15 June 2017 14:53:26 UTC+1, Mike Bayer wrote: > > > > > > > > On 06/15/2017 08:25 AM, 'mike waites' via sqlalchemy wrote: > > > Hi > > > > > > This is something i've been wrestling in different ways for some > > time so > > > i thought it was time that i sought a definitive answer on what > the > > > "proper" way to do this is with the ORM. > > > > > > Often you'll want to have some kind of scalar sub select that > > computes a > > > column in your query. This can be achieved easily by doing the > > following > > > > > > | > > > session.query(Model,scalar_sub_query).filter(...) > > > > this is likely another candidate for: > > > > > https://bitbucket.org/zzzeek/sqlalchemy/issues/3058/allow-to-inject-expression-based-columns > > > < > https://bitbucket.org/zzzeek/sqlalchemy/issues/3058/allow-to-inject-expression-based-columns> > > > > > > > > which is theoretically the very last bug I am to fix for 1.2 which I > am > > feverishly trying to get done. > > > > if you can try out the patch there and see if it applies to your use > > case too, then that's another vote for me to do this one. > > > > > > > > > | > > > > > > When passing additional column properties to the Query > > constructor like > > > this results in SQLAlchemy giving you a named tuple back. In > > some cases > > > this is fine but notice the first argument passed was Model, this > is > > > because we also want the ORM to do its normal thing of populating > an > > > instance of Model for us from the result of the query. > > > > > > In some cases this can be worked around by using declared_attr. > > This > > > will allow us to define a field that is configured at import time > > from a > > > function or something like that. This, in my experience, is > > suitable in > > > rare occasions. The moment you need something that is not setup > at > > > import time makes this unsuitable. IE suppose your column > requires a > > > user id to figure out the result. > > > > > > The next thing that comes to mind is hybrid_property. This is a > lot > > > closer to what we want in most cases, the function is deferred > until > > > query time however, to my knowledge there's no way to have > > SQLAlchemy > > > automatically populate a Model instance property from a > > hybrid_property > > > which result in use coming back to the original problem. > Specifying > > > columns explicitly results in a named tuple when we simply want > our > > > model instance populated. > > > > > > There's no doubt a way to do this but i've given up trying to > > find it. > > > > > > Hope someone can help! > > > > > > -- > > > SQLAlchemy - > > > The Python SQL Toolkit and Object Relational Mapper > > > > > > http://www.sqlalchemy.org/ > > > > > > To post example code, please provide an MCVE: Minimal, Complete, > and > > > Verifiable Example. See http://stackoverflow.com/help/mcve > > <http://stackoverflow.com/help/mcve> for a full > > > description. > > > --- > > > You received this message because you are subscribed to the > Google > > > Groups "sqlalchemy" group. > > > To unsubscribe from this group and stop receiving emails from it, > > send > > > an email to sqlalchemy+...@googlegroups.com <javascript:> > > > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:> > <javascript:>>. > > > To post to this group, send email to sqlal...@googlegroups.com > > <javascript:> > > > <mailto:sqlal...@googlegroups.com <javascript:>>. > > > Visit this group at https://groups.google.com/group/sqlalchemy > > <https://groups.google.com/group/sqlalchemy>. > > > For more options, visit https://groups.google.com/d/optout > > <https://groups.google.com/d/optout>. > > > > -- > > SQLAlchemy - > > The Python SQL Toolkit and Object Relational Mapper > > > > http://www.sqlalchemy.org/ > > > > To post example code, please provide an MCVE: Minimal, Complete, and > > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > > description. > > --- > > You received this message because you are subscribed to the Google > > Groups "sqlalchemy" group. > > To unsubscribe from this group and stop receiving emails from it, send > > an email to sqlalchemy+...@googlegroups.com <javascript:> > > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>. > > To post to this group, send email to sqlal...@googlegroups.com > <javascript:> > > <mailto:sqlal...@googlegroups.com <javascript:>>. > > Visit this group at https://groups.google.com/group/sqlalchemy. > > For more options, visit https://groups.google.com/d/optout. > -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.