I'm building a pyramid application using pyramid_tm and 
ZopeTransactionExtension.  We've written a little subscriber on NewResponse 
that writes out some values to a log file about the current user 
(request.user.id) after each request.  For anybody that knows pyramid 
pretty well, we set the request.user property 
using config.set_request_property(get_user, 'user', reify=True), but 
basically we look up the User object once in our db and then cache it as 
request.user for the lifetime of the request.

For the most part this is working fine, except for in the case that the 
User object gets modified during the request (change their avatar, name, 
password, whatever).  When this happens, we get a Detached Instance 
exception when we try to reference the 'id' field of request.user.  It's 
worth pointing out that pyramid_tm runs and commits our transaction before 
our NewResponse subscriber fires, which means that request.user has already 
been flushed and committed to the database and appears to be detached (in 
fact, we can merge it back into our session and continue using it as 
normal, see Solution #3 below).

We've found 3 work-arounds that seem to give us the desired behavior, but 
I'm not really sure which one is better.

Solution 1
----------
# setting up the session
DBSession = scoped_session(sessionmaker(bind=engine, 
extension=ZopeTransactionExtension(), expire_on_commit=False))

# in the subscriber
print request.user.id   # does 0 additional db queries

Solution 2
----------
# setting up the session
DBSession = scoped_session(sessionmaker(bind=engine, 
extension=ZopeTransactionExtension(keep_session=True)))

# in the subscriber
print request.user.id   # does an additional SELECT query


Solution 3
----------
# setting up the session
DBSession = scoped_session(sessionmaker(bind=engine, 
extension=ZopeTransactionExtension()))

# in the subscriber
session = DBSession()
user = session.merge(request.user)   # does an additional SELECT query
print user.id


Without using any of these solutions, we sure enough get the Exception:
    DetachedInstanceError: Instance <User at 0x26d5990> is not bound to a 
Session; attribute refresh operation cannot proceed


In this case, it seems Solution 1 is the best as it doesn't do any 
additional SQL queries (and I'm willing to accept that occasionally I might 
be writing a stale User object to disk), but is there any other downside to 
this approach?  After my subscriber runs the web request is finished, so 
theoretically it doesn't matter that the objects are not expired, correct? 
 Is there a better approach here that I am missing?

Thanks!

-- 
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 http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to