Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何获取由zope.transaction管理的SQLAlchemy会话,该会话与http请求具有相同的作用域,但在提交时不会自动关闭?_Python_Transactions_Sqlalchemy_Pyramid_Zope - Fatal编程技术网

Python 如何获取由zope.transaction管理的SQLAlchemy会话,该会话与http请求具有相同的作用域,但在提交时不会自动关闭?

Python 如何获取由zope.transaction管理的SQLAlchemy会话,该会话与http请求具有相同的作用域,但在提交时不会自动关闭?,python,transactions,sqlalchemy,pyramid,zope,Python,Transactions,Sqlalchemy,Pyramid,Zope,我有一个金字塔式的web应用程序,其中有一些表单页,可以从数据库中读取数据,也可以向数据库中写入数据 该应用程序将SQLAlchemy与PostgreSQL数据库一起使用,下面是我如何设置SQLAlchemy会话的: from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker from zope.sqlalchemy import ZopeTransactionExtension DBSes

我有一个金字塔式的web应用程序,其中有一些表单页,可以从数据库中读取数据,也可以向数据库中写入数据

该应用程序将SQLAlchemy与PostgreSQL数据库一起使用,下面是我如何设置SQLAlchemy会话的:

from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
在处理表单时,我需要执行
try
中包含的显式提交,并查看提交是否有效。我需要这种显式的提交,因为我在PostgreSQL数据库中有(在提交时执行的检查),并且在某些情况下,没有错误是不可预测的

一旦我成功提交了一个事务,例如添加了一个MyClass实例,我想获得这个实例上的一些属性以及链接实例上的一些属性。实际上,我无法在提交之前获取这些数据,因为它们是由数据库本身计算的

我的问题是,当我使用
transaction.commit()
(在
transaction
包中)时,会话会自动关闭,我无法再使用实例,因为它处于分离状态。证实了这一点

因此,如文档中所述,我尝试使用以下会话设置:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(keep_session=True)))
但是,现在会话作用域不再与http请求作用域相同:只执行读取查询的http请求结束时不会发送回滚


那么,有没有办法让会话与http请求具有相同的作用域,但在提交时不会自动关闭?

您可以通过中兴通讯上的
keep_session=True
将会话与请求分离。但是,如果是这种情况,您可能还希望在提交会话后使用对象,否则您会对新会话感到满意。因此,您还需要在会话中使用
expire\on\u commit=False
。在此之后,您已经成功地将会话从pyramid_tm的生命周期中分离出来,您可以根据需要提交/中止会话。那么,我们如何在不使用pyramid_tm的情况下将其重新连接到请求生命周期?好吧,如果你把你的
DBSession
包装成一个稍微不那么全局的东西,这将使它作为一个请求范围的变量更易于管理,这会有所帮助。从这里可以明显看出,会话何时创建,何时应该通过请求完成回调销毁。以下是我的散文摘要:

def get_db(request):
    session = request.registry['db_session_factory']()
    def _closer(request):
        session.close()
    request.add_finished_callback(_closer)
    return session

def main(global_conf, **settings):
    config = Configurator()

    DBSession = sessionmaker(expire_on_commit=False, extension=ZopeTransactionExtension(keep_session=True))
    # look we don't even need a scoped_session anymore because it's not global, it's local to the request!

    config.registry['db_session_factory'] = DBSession

    config.add_request_method('db', get_db, reify=True)

def myview(request):
    db = request.db # creates, or reuses the session created for this request
    model = db.query(MyModel).first();
    transaction.commit()
    # model is still valid here
    return {}

当然,如果我们在做这些事情,中兴通讯可能根本帮不了你,你只想使用
db.commit()
自己处理事情。如果发生异常,完成的回调仍将被调用,因此您不需要pyramid_tm在之后进行清理。

正如我所编辑的,这更像是zope.transaction/pyramid集成问题。您可能希望在金字塔邮件列表上请求更快的响应。它可以完美地工作,除非我的提交在
try
块中失败。实际上,我在
块中执行了
事务.abort()
,但这似乎不够,因为当我再次尝试使用该会话时,我会收到一个错误:
InvalidRequestError:由于刷新期间的前一个异常,该会话的事务已回滚。要使用此会话开始新事务,请首先发出Session.rollback()。最初的异常是…
。添加
request.db.rollback()
解决了问题,但我不得不同时使用
Transaction.abort()
Session.rollback()
,这两种方法看起来都不干净。如果你在做这些事情,我不确定中兴通讯是否在帮助你。没错,我只是为了理解而问。