'SQLAlchemy: Using sessionmaker as contextmanger forces to expunge manually
I'm using SQLAlchemy and trying to use the sessionmaker as a context manager for my transaction (following the documentation):
Session = sessionmaker(some_engine)
with Session.begin() as session:
query = session.query(SomeTable)
an_entry = query.one()
# session.expunge_all() # Fixes the exception
an_entry.attribute
Which raises an sqlalchemy.orm.exc.DetachedInstanceError: Instance <AnEntry at 0x7f0a9d1c2560> is not bound to a Session
exception. This can be solved by expunging inside the contextmanager (see the line commented out above).
I'm surprised by this behavior, as the SQLAlchemy documentation and code indicate that closing a session should automatically expunges all ORM objects. And indeed, the following equivalent of the above works, without me having to manually expunge:
Session = sessionmaker(some_engine)
session = Session()
with session.begin():
query = session.query(SomeTable)
an_entry = query.one()
an_entry.attribute
Can anyone explain this behavior?
Solution 1:[1]
In the second, "working" example, the context manager is the SessionTransaction
object returned by session.begin
, not the session itself. The session is not closed before accessing the attribute and therefore there is no DetachedInstanceError
: the instance is never expunged.
A better comparison might be why this code does not raise an error:
with Session() as s:
an_entry = s.query(SomeTable).one()
an_entry.attribute
The reason is that it does not commit. By default, ORM objects are expired when a commit occurs, so a subsequent attribute access requires a query to get the value. In the case of with Session.begin() as session:
, the session is committed on leaving the with block, so accessing the attribute requires a query, which requires that the object be attached to a session.
Session
and sessionmaker
both accept an expire_on_commit
boolean keyword argument to control this behaviour.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | snakecharmerb |