如何在上下文管理器中使用 SQLAlchemyscoped_session?

Wyk*_*aar 0 python sqlalchemy

根据文档,我们应该对对象使用以下模式sessionmaker

Session = sessionmaker(engine)
with Session.begin() as session:
    session.add(some_object)
Run Code Online (Sandbox Code Playgroud)

在多线程环境中,我们也应该使用单线程scoped_session并共享它。因此,在我的程序中__init__.py,我创建了一个并将其导入到程序中的其他位置:

engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
Session = scoped_session(sessionmaker(bind=engine))
Run Code Online (Sandbox Code Playgroud)

问题是,我应该如何结合这两种方法?这似乎是建议的方式,但它出错了:

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'
Run Code Online (Sandbox Code Playgroud)

我尝试了以下方法并且它有效,但它似乎不遵循文档,而且我担心它会破坏一些不明显的东西。谁能确认这是否正确?

from myapp import Session
with Session() as session, session.begin():
    query_result = session.query(MyModel).all()
Run Code Online (Sandbox Code Playgroud)

我一直在查看其他回复,但几乎没有看到解决具体问题的答案。

ljm*_*jmc 5

来自Session.begin()文档

Session对象具有自动开始行为,因此通常不需要Session.begin()显式调用该方法。然而,它可以用于控制事务状态何时开始的范围。

您可以使用Session.begin()(1.4 中的新增功能)获取SessionTransaction可用作上下文管理器的实例,该实例将在成功退出时自动提交。

根据您的错误,立即调用scoped_session返回 a SessionTransaction,因此您无需再次开始。

总而言之,您绝对可以使用堆叠上下文管理器,但它没有必要,因此您不妨坚持使用原始流程

Session = scoped_session(...)

with Session() as session:  # NB. session is a thread local SessionTransaction
    ...
    session.commit()
Run Code Online (Sandbox Code Playgroud)

或代理的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()
Run Code Online (Sandbox Code Playgroud)