<blockquote>
<p>Could this be from an earlier transaction.commit() in another method?</p>
</blockquote>
<p><strong>是,</strong>如果在同一请求-响应周期内调用另一个方法-一旦提交事务,SQLAlchemy无法保证内存中的ORM对象仍然代表数据库的实际状态,因此,如果不显式地将现在分离的对象合并到新的会话中,就不能在一个事务中获取对象并将其保存回另一个事务中。在</p>
<p><strong>您通常不应该在代码中使用<code>transaction.commit()</code>。</strong>使用<code>ZopeTransactionExtension</code>背后的想法是它将SQLAlchemy事务与Pyramid的请求-响应周期联系在一起-当请求启动时,将构造一个新的会话,如果请求在视图中提交失败,则返回。在代码中,您不应该关心提交任何内容—只需将新对象添加到会话中:</p>
<pre><code>@view_config(route_name='create_location', renderer='templates/main.html')
def create_location(request):
#get the json data from the ajax call
data = request.json_body
customer = DBSession.query(Customer).filter(Customer.id==data["custID"]).one()
session.add(Location(description=data["location"], customer=customer))
return Response('ok')
</code></pre>
<p><em>(忍不住让代码更像“普通”Python代码。。。匈牙利符号是。。。呃。。。现在不是很常用。。。谢谢你给了我一个怀旧的闪回:))见<a href="http://legacy.python.org/dev/peps/pep-0008/" rel="nofollow">PEP 8</a>详情)。</em></p>
<p>在<em>很少的</em>情况下,您可能希望请求的某些部分成功,或者甚至只在发生错误时才将数据保存到数据库(例如,将错误记录到数据库中)。在这些情况下,您将使用一个单独的会话,该会话没有配置ZopeTransactionExtension。您需要手动提交此类会话:</p>
^{pr2}$
<p>进一步阅读:</p>
<ul>
<li><p><a href="http://docs.sqlalchemy.org/en/rel_0_9/orm/session.html#session-faq-whentocreate" rel="nofollow">When do I construct a Session, when do I commit it, and when do I close it?</a>-SQLAlchemy文档中的高级概述。”TL;DR:一般来说,将会话的生命周期与访问和/或操作数据库数据的函数和对象分开并在外部进行。”请注意,金字塔已经为您完成了所有的会话管理—独立于代码的外部结束。</p></li>
<li><p><a href="http://pyramid-tutorials.readthedocs.org/en/latest/getting_started/11-sqlalchemy/#application-steps" rel="nofollow">Databases Using SQLAlchemy</a>-一个使用SQLAlchemy的基本金字塔应用程序。请参见<code>dev wikipage_add()</code>函数,以获取将一些数据保存到数据库的典型代码的示例。</p></li>
</ul>