读取分离的sqlalchemy对象的属性会引发DetachedInstanceE

2024-04-20 10:59:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用短期的sqlalchemy会话向sqlite数据库添加对象。一些对象在只读、分离状态下比会话寿命长。不幸的是,如果会话已关闭,访问分离对象的属性会引发异常。下面是一个简化的代码示例

from sqlalchemy import Column, String, Integer, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

engine = create_engine('sqlite:///foo.db', echo=False)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

f = Foo(name='foo1')
print('state=transient : name=', f.name)
session.add(f)
print('state=pending : name=', f.name)
session.commit()
session.close()
print('state=detached : name=', f.name)
# output
state=transient : name= foo1
state=pending : name= foo1
Traceback (most recent call last):
  File "scratch_46.py", line 23, in <module>
    print('state=detached : name=', f.name)
  File "lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 282, in __get__
    return self.impl.get(instance_state(instance), dict_)
  File "lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 705, in get
    value = state._load_expired(state, passive)
  File "lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 660, in _load_expired
    self.manager.deferred_scalar_loader(self, toload)
  File "lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 913, in load_scalar_attributes
    "attribute refresh operation cannot proceed" % (state_str(state))
sqlalchemy.orm.exc.DetachedInstanceError: Instance <Foo at 0x7f266c758ac8> is not bound to a Session; attribute refresh operation cannot proceed (Background on this error at: http://sqlalche.me/e/bhk3)

奇怪的是,如果我执行以下任一操作,就不会抛出错误

  • 当对象处于持久状态时,读取commit和close调用之间的name属性
  • 从会话中删除对象并使会话保持打开状态。仍然是分离状态,但我可以访问属性。你知道吗

我应该能够读取分离对象的属性吗?有没有一种方法可以让对象安全地超过临时会话?我阅读了输出中建议的链接,但它主要讨论父/子关系。你知道吗

我在sqlalchemy repo上创建了一个an issue,因为一开始我认为这是一个bug,但现在我不太确定了。你知道吗


Tags: 对象nameinpy属性sqlalchemysession状态
1条回答
网友
1楼 · 发布于 2024-04-20 10:59:14

深入研究后发现,会话中的默认值expire_on_commit为真,这使我得到了一些好处。启用该选项后,commit调用将使对象过期,这迫使sqlalchemy在下次有人读取属性时重新加载它。如果延迟到会话关闭之后,则无法获取属性。你知道吗

我真的不希望这种自动过期,因为我知道我的对象处于良好状态,并且在保存后是只读的。在会话生成器中将expire_on_commit设置为false可以解决问题。你知道吗

相关问题 更多 >