def get_new():
sess = Session()
new = Something() # new orm object
sess.add(new)
sess.commit()
sess.close()
return new
new = get_new() # request a new Something
print new
print new.id
Those last 2 print lines throw:
DetachedInstanceError: Instance <Something at 0x2873ed0> is not bound to
a Session; attribute refresh operation cannot proceed
I seem to keep butting heads with the session needing to be a global eternal
thing (opposite what the docs recommend). I could create another session and
add 'new' to it, but that seems like a lot of boilerplate when all I wanted to
do was get a bit of info from the returned object.
Can someone explain how this is supposed to be done?
Thanks,
Michael
I'm obviously missing some key concept as regards the management of sessions. This seemingly simple usage fails:
def get_new():
sess = Session()
new = Something() # new orm object
sess.add(new)
sess.commit()
sess.close()
return new
new = get_new() # request a new Something
print new
print new.id
Those last 2 print lines throw:
DetachedInstanceError: Instance <Something at 0x2873ed0> is not bound to
a Session; attribute refresh operation cannot proceed
I seem to keep butting heads with the session needing to be a global eternal thing (opposite what the docs recommend).
Can someone explain how this is supposed to be done?
Thanks for taking the time to formulate a very thorough answer. (Now if I can
make my understanding be as thorough.)
If you could suffer me one more question ... it appears there are two* ways to
handle this inside a method that may not know where it's called from.
def alternative1(thing):
sess = Session()
sess.merge(thing)
thing.name = "Foo"
sess.commit()
sess.close()
def alternative2(thing, sess=None):
if sess is None:
sess = Session()
sess.merge(thing)
thing.name = "Foo"
sess.commit() # incomplete, must do sess.close()
Am I getting anywhere close? Can either one be said to be better?
Again, thanks.
Michael
* For now, I'm taking it as an article of faith that I should stay away from
expire_on_commit at least until I better understand the implications.
> <http://www.sqlalchemy.org/docs/reference/orm/sessions.html#sqlalchemy.orm.session.Session.commit>
> Michael
>
> Thanks for taking the time to formulate a very thorough answer. (Now if I can make my understanding be as thorough.)
>
> If you could suffer me one more question ... it appears there are two* ways to handle this inside a method that may not know where it's called from.
>
> def alternative1(thing):
> sess = Session()
> sess.merge(thing)
> thing.name = "Foo"
> sess.commit()
> sess.close()
>
> def alternative2(thing, sess=None):
> if sess is None:
> sess = Session()
> sess.merge(thing)
> thing.name = "Foo"
> sess.commit() # incomplete, must do sess.close()
>
> Am I getting anywhere close? Can either one be said to be better?
If you're looking for that approach, it is usually:
from sqlalchemy.orm import object_session
def foo(thing):
session = object_session(thing)
if not session:
local_sess = Session(expire_on_commit=False)
local_sess.add(thing)
thing.name = 'foo'
if not session:
local_sess.commit()
What we've done above is, if the "thing" is already part of a session, we don't assume to know what the state of the transaction is - we don't commit it. If it was detached, and we made our own session, then we committed it.
You can also make a decorator that does the same:
import decorator # pypi package
@decorator
def force_a_session(fn, item):
session = object_session(item)
if not session:
local_sess = Session(expire_on_commit=False)
local_sess.add(item)
try:
try:
return fn(item)
finally:
if not session:
local_sess.commit()
except:
if not session:
local_sess.rollback()
raise
The approach above may be fine for your needs but I wouldn't encourage it. The demarcation of transaction boundaries shouldn't be an ad-hoc thing IMO and granular functions shouldn't be deciding whether or not they are setting up a transaction.
> --
> You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
> To post to this group, send email to sqlal...@googlegroups.com.
> To unsubscribe from this group, send email to sqlalchemy+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
>
Thanks. Yes, I was beginning to suspect such. Makes more sense to manage the
session and commit/rollback issues at the top of the call stack. I was trying
too hard to not have to pass the session down in argument lists, but looks like
I should.
Thanks,
Michael
well, you can either call object_session() in the methods to get the current object's session, or set up a registry like scoped_session that you access globally - I'd try to avoid having to pass the session around too.