Load columns/relationships of transient objects

538 views
Skip to first unread message

Harshvardhan Gupta

unread,
Mar 2, 2018, 12:38:08 AM3/2/18
to sqlalchemy
I am using flask-sqlalchemy , and flask login. 

Flask login requires a user object to identify the current user. 

So I give it something like : 

user = User(id=1)

where User is an flask-sqlalchemy db model. 

Note that this does not actually perform a query to the db. 

Later on, I may want to access the email attribute of user, so I would do : 
user.email. 
Now I would expect a db query to be run and fetch the email from the database. 

There seems to be some discussion about this issue , but I was unable to find a proper solution for it. 

Some help will be great

Mike Bayer

unread,
Mar 2, 2018, 10:48:50 AM3/2/18
to sqlal...@googlegroups.com
the correct solution would be to please load the User object from the
database so that you avoid having to guess that User(id=1) even exists
or is a valid user.

The less correct solution tis that you can associate this
not-necessarily-existing User object with a Session to provide
relationship lazy loading using the enable_relationship_loading()
method on your object:
http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.enable_relationship_loading


>
> --
> 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.
> To post to this group, send email to sqlal...@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

Harshvardhan Gupta

unread,
Mar 2, 2018, 10:52:21 AM3/2/18
to sqlalchemy
Thanks for the reply.

There is a guarantee that the user will exist ,why is why I want to prevent that extra db query.

When I try to do enable relationship loading ,I get the error :
Scoped session has no attribute enable relationship loading.

Mike Bayer

unread,
Mar 2, 2018, 10:55:11 AM3/2/18
to sqlal...@googlegroups.com
that's a scoped_session(), not a Session, access the Session by
calling it: scoped_session().enable_relationship_loading(obj)

Harshvardhan Gupta

unread,
Mar 2, 2018, 11:00:47 AM3/2/18
to sqlalchemy
Thanks, I am able to call my object, but the attribute prints none: 


E.g. my model is: 

class User(Dictifiable, db.Model, UserMixin):
__tablename__ = 'user'

id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
full_name = Column(String(50))

And this is what I have done : 

`u_lazy = User(id=1)`
`db.session().enable_relationship_loading(u_lazy)`
when i try to print u_lazy.full_name, it shows null (it is non null in db  ) 
Message has been deleted

Harshvardhan Gupta

unread,
Mar 2, 2018, 11:21:44 AM3/2/18
to sqlalchemy
I also tried loading a related attribute , and it still returns None. 

Mike Bayer

unread,
Mar 2, 2018, 11:27:31 AM3/2/18
to sqlal...@googlegroups.com
On Fri, Mar 2, 2018 at 11:21 AM, Harshvardhan Gupta
<harsh...@gmail.com> wrote:
> I also tried loading a related attribute , and it still returns None.


you need to merge the object:

my_user = session.merge(my_user)

that is your only option. E.g. do the query.

Harshvardhan Gupta

unread,
Mar 2, 2018, 11:30:52 AM3/2/18
to sqlalchemy
There is no way to achieve what I want without doing the query? 
merge seems to do the whole query. 
I also have asked this question on stack overflow which talks about my use case : 

Mike Bayer

unread,
Mar 2, 2018, 11:51:20 AM3/2/18
to sqlal...@googlegroups.com
On Fri, Mar 2, 2018 at 11:30 AM, Harshvardhan Gupta
<harsh...@gmail.com> wrote:
> There is no way to achieve what I want without doing the query?
> merge seems to do the whole query.

you have a User row, and you want to load columns in that row, like
"full_name". How would you like to achieve that without emitting a
query?

Harshvardhan Gupta

unread,
Mar 2, 2018, 11:55:00 AM3/2/18
to sqlalchemy
I meant, do the query only when email is required, and not unless anything else is required. 
if I call merge(), the query is instantly emitted. I want it to be emitted only if an unloaded attribute is requested. 

Mike Bayer

unread,
Mar 2, 2018, 11:55:43 AM3/2/18
to sqlal...@googlegroups.com
On Fri, Mar 2, 2018 at 11:55 AM, Harshvardhan Gupta
<harsh...@gmail.com> wrote:
> I meant, do the query only when email is required, and not unless anything
> else is required.
> if I call merge(), the query is instantly emitted. I want it to be emitted
> only if an unloaded attribute is requested.

make the object act like detached and expired, then associate with the session:

from sqlalchemy.orm.session import make_transient_to_detached
a1 = A(id=1)
make_transient_to_detached(a1)
s.add(a1)

print("-------------------")
assert a1.data == "some data"
assert len(a1.bs) == 3

Mike Bayer

unread,
Mar 2, 2018, 11:56:30 AM3/2/18
to sqlal...@googlegroups.com
please add an answer to your stackoverflow question as well

Harshvardhan Gupta

unread,
Mar 2, 2018, 12:15:55 PM3/2/18
to sqlalchemy
Thanks! 
make_transient_to_detached did the trick! 

ill add the answer to my question. 
Reply all
Reply to author
Forward
0 new messages