14

我想从我的会话中分离一个类的实例,但它应该仍然可以读取(不发出查询)。我已经浏览了好几天的文档,但是我尝试的每种方法都会导致消息

DetachedInstanceError: Instance <MyModel at 0x36bb190> is not bound to a Session;
attribute refresh operation cannot proceed

我正在与zope.sqlalchemyPyramid 的事务管理器一起工作。我希望我的对象在事务提交可用。我只需要它来读取“缓存”值,即事务提交之前其中的值。

我能找到的唯一可能的解决方案是包装类(或属性本身),然后手动跟踪更改(我可以这样做,但它真的很难看,而且根本不是 Pythonic)。

有没有办法阻止 SQLAlchemy 尝试刷新这些值?

作为后备,我什至愿意只返回None,只要在事务提交后没有抛出上述错误

4

4 回答 4

12

您可以通过执行以下操作来做到这一点(例如缓存):

session.expunge(obj)

根据 sqlalchemy 文档:

http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html?highlight=expire#sqlalchemy.orm.session.Session.expunge

这将为您提供处于分离状态的对象,您可以安全地使用 - 您需要记住,您将无法读取会发出另一个查询的属性,因此与类似会话的关系相关联,这将以DetachedInstanceError.

默认情况下,提交将发出 expire_all() ,这意味着所有对象将在读取时刷新它们的状态,通过删除它们,您将它们从会话中分离出来,因此在提交事务后不应有后续查询。

我建议不要在全球范围内禁用此功能,因为其他评论建议迈克拜尔通常认为这是一个好主意,并且对于大多数人来说是一个理智的默认设置,从长远来看可以让你头疼。

只是在你需要的时候明确地删除它们。

于 2015-07-14T23:16:57.520 回答
11

http://docs.sqlalchemy.org/en/latest/orm/session_api.html

我想你正在寻找expire_on_commit = False

我相信这可以让您分离对象并继续使用它。然而,尝试修改它并提交将导致DetachedInstanceError.

于 2013-04-20T01:33:59.517 回答
4

尝试这个:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False))

我也有这个问题,使用expire_on_commit=False解决了我的问题。

于 2015-01-11T17:18:07.103 回答
3
@contextmanager
def make_session_scope(Session):
    """Provide a transactional scope around a series of operations."""
    session = Session()
    session.expire_on_commit = False
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

 with make_session_scope(session) as session:
      query = session.query(model)
于 2015-12-08T03:06:19.087 回答