sqlalchemy对象如何分离?

时间:2013-11-06 16:59:24

标签: python sqlalchemy flask flask-sqlalchemy

我的代码结构如下:

project
--app
----utils
------util.py
----__init__.py
----models.py
--tests
----__init__.py

在tests / __ init__.py中,我有代码通过从app / __ init__.py导入所有应用程序来初始化应用程序(如果重要的话)。我可以在tests / __ init__.py中创建模型,查询和访问backrefs的实例。以下表格的代码可以正常工作:

objs = SomeModel.query.all()
for o in objs:
    o.backref

但是,如果我这样做:

from utils.util import some_function
objs = SomeModel.query.all()
for o in objs:
    some_function(o)

其中some_function只访问backref

def some_function(obj):
    obj.backref

我收到类似DetachedInstanceError: Parent instance <SomeModel at 0x2c1fe10> is not bound to a Session; lazy load operation of attribute 'backref' cannot proceed

的错误

阅读sqlalchemy文档表明我需要将对象重新关联到数据库sesssion。我这样做了,看起来它的工作原理(即运行函数不会因上一个错误而失败):

import db_session
def some_function(obj):
    db_session.add(obj)
    obj.backref

那么一个物体到底是什么时候分开的?似乎只是将对象传递给另一个模块中的函数将其从会话中分离出来。对象是否不知道与之关联的sqlalchemy会话?我试图避免做db_session.add(obj)这似乎是很多样板代码。

1 个答案:

答案 0 :(得分:3)

我在自己similar question处理属性到期时遇到了这个问题。实例分离。 univerio给了我一个很好的答案,而且从我学到的东西中,我可能能够对你的问题有所了解。

在我的情况下,我正在创建,提交或回滚,然后在单个Session子句的范围内关闭with...as...,然后尝试访问我保存的实例({{紧接着但在obj子句范围之外的示例中的1}}。在我尝试引用保存的对象之前,with被关闭了。 默认情况下,在SQLAlchemy中,如果没有活动 Session,则无法访问持久化的属性/对象,除非明确告知允许它。这是为了保护&#34;通过强制应用程序首先查询/检索更新的数据来意外或不知情地使用过时/不正确数据的代码,这需要关联的Session。所以在我的情况下,在提交后保持Session打开意味着该对象可以使用Session来查询数据库,以防记录在首次编写后被修改。

在您的情况下,Session用于通过Session获取对象的objs = SomeModel.query.all()在查询后但在obj.backref被调用之前被关闭或断开(尽管我不是确定如何;我不知道SomeModel是什么,确切地说,我假设是Flask的一个构造,在其背景中包含Session。所以obj不再与数据库建立连接,因此&#34;已分离&#34;。通过将其添加到db_session,您允许obj重新建立与其源数据库的连接,通过它可以查询以检查更新的属性,因此它不再分离。

最后,值得一提的是,DetachedInstanceError可以通过指定与Session关联的原始obj而不是过期来避免obj属性自动。如果过期 obj,则不会抛出错误,obj.backref仍然会分离 ,意思是当您调用obj时,返回的值可能不正确/过时。您询问了在问题中的分离,但过期是一个相关但不完全相同的概念。

除此之外 - 如何设置Session不会过期:my_session = sessionmaker(expire_on_commit=False 的初始化

sessionmaker

my_sessionmaker = sqlalchemy.orm.sessionmaker(expire_on_commit=False) 的初始化

Session

或甚至在my_session.expire_on_commit = False 已经实例化后

for (int number = 0; number <= students; number++, comp++) {
                System.out.println(comp); //random is an object
        }