'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