Reputation: 158
Per the docs, we should use the following pattern with a sessionmaker
object:
Session = sessionmaker(engine)
with Session.begin() as session:
session.add(some_object)
In a multithreaded environment, we are also supposed to use a single scoped_session
and share it. So in my __init__.py
I create create one and import it everywhere else in my program:
engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
Session = scoped_session(sessionmaker(bind=engine))
The question is, how am I supposed to combine these two approaches? This seems to be the suggested way, but it errors out:
from myapp import Session
with Session.begin() as session:
query_result = session.query(MyModel).all()
----
Exception has occurred: AttributeError
'SessionTransaction' object has no attribute 'query'
I tried the following and it works, but it seems like it doesn't follow the docs, and I'm afraid it breaks something not obvious. Can anyone confirm if this is correct?
from myapp import Session
with Session() as session, session.begin():
query_result = session.query(MyModel).all()
I've been looking around at other replies and seeing very little that addresses the specific question.
Upvotes: 1
Views: 5128
Reputation: 5315
From the Session.begin()
docs:
The
Session
object features autobegin behavior, so that normally it is not necessary to call theSession.begin()
method explicitly. However, it may be used in order to control the scope of when the transactional state is begun.
You can use Session.begin()
(new in 1.4) to obtain a SessionTransaction
instance usable as a context manager which will autocommit on successful exit.
Calling the scoped_session
returns a SessionTransaction
right away, as per your error, so you do not need to begin it again.
All in all, you can definitely do the stacked context manager, but its unnecessary, so you might as well stick to using the original flow:
Session = scoped_session(...)
with Session() as session: # NB. session is a thread local SessionTransaction
...
session.commit()
or the proxied Session
Session = scoped_session(...)
@on_request_end
def remove_session(req):
Session.remove()
@route("/xyz", ...)
def handle_xyz():
instance = Class(...)
Session.add(instance)
Session.commit()
Upvotes: 8