具有常规属性(不是关系)的SQLAlchemy DetachedInstanceError

我刚开始使用SQLAlchemy并得到一个DetachedInstanceError,并且无法在任何地方find很多信息。 我在会话外部使用实例,所以很自然的是,如果SQLAlchemy没有加载任何关系,它是无法加载的,但是我访问的属性并不是一个关系,事实上这个对象根本就没有关系。 我发现解决scheme,如急于加载,但我不能适用于此,因为这不是一个关系。 我甚至在closures会话之前试着“触摸”这个属性,但是它仍然不能防止这个exception。 甚至在它被成功访问一次之前,什么可能导致这个非关系属性的exception呢? 任何帮助在debugging这个问题表示赞赏。 我将同时尝试获得可重复的独立场景并在此处进行更新。

更新:这是几个堆栈的实际exception消息:

File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/attributes.py", line 159, in __get__ return self.impl.get(instance_state(instance), instance_dict(instance)) File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/attributes.py", line 377, in get value = callable_(passive=passive) File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/state.py", line 280, in __call__ self.manager.deferred_scalar_loader(self, toload) File "/home/hari/bin/lib/python2.6/site-packages/SQLAlchemy-0.6.1-py2.6.egg/sqlalchemy/orm/mapper.py", line 2323, in _load_scalar_attributes (state_str(state))) DetachedInstanceError: Instance <ReportingJob at 0xa41cd8c> is not bound to a Session; attribute refresh operation cannot proceed 

部分模型看起来像这样:

 metadata = MetaData() ModelBase = declarative_base(metadata=metadata) class ReportingJob(ModelBase): __tablename__ = 'reporting_job' job_id = Column(BigInteger, Sequence('job_id_sequence'), primary_key=True) client_id = Column(BigInteger, nullable=True) 

并且字段client_id是什么导致这个例外用法如下:

查询:

  jobs = session \ .query(ReportingJob) \ .filter(ReportingJob.job_id == job_id) \ .all() if jobs: # FIXME(Hari): Workaround for the attribute getting lazy-loaded. jobs[0].client_id return jobs[0] 

这就是在会话范围之后触发exception:

  msg = msg + ", client_id: %s" % job.client_id 

我在试图缩小导致exception的代码时find了根本原因。 在会话closures后,我在不同的地方放置了相同的属性访问代码,发现查询会话closures后,不会立即引发任何问题。 事实certificate,问题开始出现后,closures一个新的会议,打开更新对象。 一旦我了解到会话closures后对象的状态是不可用的,我就能find讨论这个相同问题的这个线程 。 来自线程的两个解决scheme是:

  • 保持一个会话打开(这是显而易见的)
  • sessionmaker()指定expire_on_commit=False

第三个选项是在会话创build后手动将expire_on_commit设置为False ,如: session.expire_on_commit = False 。 我证实这解决了我的问题。

我们得到类似的错误,即使expire_on_commit设置为False 。 最后实际上是由于有两个sessionmaker被用来在不同的请求中创buildsession。 我真的不明白发生了什么,但是如果你看到expire_on_commit=False这个exception,请确保你没有初始化两个sessionmaker

至于我(新手),我在缩进上犯了一个错误,并closures了我的循环内的会话,其中我循环每一行,做一些操作和每次提交。

所以对于像我这样的新手来说,在设置诸如expire_on_commit=False类的东西之前请检查一下你的代码,这可能会导致你陷入另一个陷阱。