Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detaching SQLAlchemy instance so no refresh happens

I want to detach an instance of a class from my session but it should still be available for reading (without emitting a query). I have been scanning through the documentation for days now, but every approach I try leads to the message

DetachedInstanceError: Instance <MyModel at 0x36bb190> is not bound to a Session;
attribute refresh operation cannot proceed

I am working with the zope.sqlalchemy transaction manager in Pyramid. I want my object to be usable after the transaction has been committed. I only need it to read the "cached" value, i.e. those that were in it before the transaction was commited.

The only possible solution I could find was to wrap the class (or the attributes itself) and then track the changes manually (I could do that but it is really ugly and not at all Pythonic).

Is there a way I can prevent SQLAlchemy from trying to refresh these values?

As a fallback I would even be open to just returning None, as long as the above error doesn't get thrown after the transaction as been committed

like image 885
javex Avatar asked Mar 13 '13 22:03

javex


People also ask

What does refresh do in SQLAlchemy?

The Session. expire() and Session. refresh() methods are used in those cases when one wants to force an object to re-load its data from the database, in those cases when it is known that the current state of data is possibly stale.

How do you close a SQLAlchemy Session?

A SQLAlchemy Session generally represents the scope of one or more transactions, upon a particular database connection. Therefore, the answer to your question as literally asked, is to call session. close() , that is, "how to properly close a SQLAlchemy session".

What is lazy dynamic SQLAlchemy?

lazy = 'dynamic': When querying with lazy = 'dynamic', however, a separate query gets generated for the related object. If you use the same query as 'select', it will return: You can see that it returns a sqlalchemy object instead of the city objects.

What is lazy in flask SQLAlchemy?

Lazy loading refers to objects are returned from a query without the related objects loaded at first. When the given collection or reference is first accessed on a particular object, an additional SELECT statement is emitted such that the requested collection is loaded.


1 Answers

You can do exactly this (for example for caching) by doing:

session.expunge(obj)

As per sqlalchemy documentation:

http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html?highlight=expire#sqlalchemy.orm.session.Session.expunge

This will give you object that is in detached state that you can safely use - you need to remember you will not be able to read properties that would emit another query thus being tied to session - like relationship, this will end up with DetachedInstanceError.

By default a commit will issue an expire_all() which means all objects will refresh their state on read, by expunging them you detach them from the session so there should be no subsequent queries after you commit your transaction.

I would advise against disabling this functionality globally as the other comments suggest as Mike Bayer generally suggest it is a good idea and a sane default for most people that can save you headaches in long run.

Just expunge things explictly when you need them.

like image 78
Ergo Avatar answered Sep 19 '22 07:09

Ergo