分离SQLAlchemy实例以避免刷新
我想把一个类的实例从我的会话中分离出来,但仍然希望它可以被读取(不需要再发起查询)。我已经翻阅文档好几天了,但我尝试的每种方法都让我看到这个提示
DetachedInstanceError: Instance <MyModel at 0x36bb190> is not bound to a Session;
attribute refresh operation cannot proceed
我在Pyramid中使用zope.sqlalchemy
的事务管理器。我希望我的对象在事务提交后仍然可以使用。我只需要读取“缓存”的值,也就是在事务提交之前的那些值。
我找到的唯一可能的解决办法是把这个类(或者它的属性)包裹起来,然后手动跟踪变化(我可以这样做,但这真的很麻烦,而且一点也不符合Python的风格)。
有没有办法可以阻止SQLAlchemy尝试刷新这些值呢?
作为备选方案,我甚至可以接受返回None
,只要在事务提交后不再出现上面的错误提示就行。
4 个回答
试试这个:
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False))
我也遇到过这个问题,使用 expire_on_commit=False
解决了我的问题。
你可以通过以下方式实现这个功能(比如用于缓存):
session.expunge(obj)
根据sqlalchemy的文档:
这样你就能得到一个处于“分离状态”的对象,这个对象可以安全使用。你需要记住的是,不能读取那些会触发新查询的属性,这样会和会话绑定在一起,比如关系属性,这样会导致出现DetachedInstanceError
错误。
默认情况下,提交操作会执行一个expire_all(),这意味着所有对象在读取时都会刷新它们的状态。通过将对象分离,你把它们从会话中移除,这样在提交事务后就不会有后续的查询了。
我建议不要像其他评论所说的那样全局禁用这个功能,因为Mike Bayer通常认为这对大多数人来说是个好主意,也是一个合理的默认设置,能在长远中避免麻烦。
只在需要的时候明确地分离对象。
我觉得你在找的是 expire_on_commit = False
我相信这个设置可以让你把对象分离出来,然后继续使用它。不过,如果你尝试去修改这个对象并提交的话,就会出现 DetachedInstanceError
的错误。