将预构建的查询附加到SQLAlchemy中的scoped_session

时间:2017-04-28 17:28:15

标签: python session sqlalchemy

尝试在SQLAlchemy ORM中的scoped_session上执行预构建查询时,我收到一个奇怪的错误AttributeError: 'scoped_session' object has no attribute '_autoflush'

我正在使用上下文管理器来产生一个scoped_session,

@contextmanager
def connect(my_session_factory):
    session = scoped_session(my_session_factory)
    try:
        yield session
    except Exception as exception:
        session.rollback()
        raise exception
    finally:
        session.close()

然后就像这样使用它:

from sqlalchemy.orm import Query

query = Query(my_model).offset(my_offset).limit(my_limit)
with connect(my_session_factory) as session:
    instances = query.with_session(session).all()
    return instances

然而,这引发了上述例外。

我还注意到session.query(my_model)形式的查询工作正常。

我哪里错了?非常感谢!

1 个答案:

答案 0 :(得分:3)

好的 - 我没有对提出的问题给出答案,但我似乎确实有一个解决方法。

问题似乎与scoped_session对象的代理行为有关。据我了解,scoped_session()方法采用sessionmaker对象并使用它来创建线程局部session对象。但是,scoped_session()方法不会返回此线程本地session。相反,它返回一个scoped_session对象,以某种方式(我不完全清楚)容纳线程本地session。要直接访问此线程本地会话,您可以执行scoped_session.registry(),或者只需scoped_session() scoped_session这里有一个scoped_session 对象已由scoped_session方法返回。

my_scoped_session = scoped_session(my_session_factory)
my_local_session = my_scoped_session()

现在问题在于:由于my_scoped_session.query(...).all()对象的代理行为,文档似乎表明my_local_session.query(...).all()scoped_session等调用是等效的。我发现这在大多数情况下是正确的,但在我原来的问题情况下并非如此。

如果您执行my_query = Query(...)(即构建非会话绑定查询),然后将其附加到scoped_session对象(希望利用scoped_session代理机制,例如在my_query线程本地scoped_session的上下文中处理session,通过my_instances = my_query.with_session(my_scoped_session).all()或类似方式,您可以在我的原始问题中获得回溯。

我的解决方法是完全跳过scoped_session对象的代理机制,而是将my_query直接绑定到my_local_session

my_query = Query(...).filter(...).sort(...)
my_instances = my_query.with_session(my_local_session).all()

这似乎有效。但是,如果有人想关注直接使用scoped_session(my_session_factory)()而不是scoped_session(my_session_factory)(大多数在线教程似乎都是这样)的危险(如果有的话),那么我会不胜感激!