在 Pyramid 中管理 Pony 会话
Manage Pony session in Pyramid
以下代码抛出 DatabaseSessionIsOver
异常,如 this post 中所述:
@view_config(route_name='home', renderer='templates/home.jinja2')
@orm.db_session()
def home(self):
x = models.Entity(...)
return {'x': x}
我使用 return render_to_response('templates/home.jinja2', {'x': x})
解决了这个问题,它是上面提到的 post 中建议的 render_template()
的金字塔等价物。
一切正常,但我认为有更好的解决方案:我认为我应该让 Pyramid 管理 Pony 会话。
可能吗?
我该怎么做?
您的问题是您要从视图返回托管对象 x
,然后在呈现视图的响应之前关闭 orm 会话。您希望会话包装请求生命周期的大部分,以便您的托管对象保持更长的生命周期。对于数据库会话之类的东西,补间确实是处理此问题的最佳方法,但还有其他一些方法,例如请求 属性 request.pony_session
和可以关闭会话的完成回调的组合.例如(对不起,我实际上不知道小马的 api 所以你必须填写实际的方法):
def get_pony_session(request):
session = ... # load a pony session somehow
def cleanup(request):
try:
if request.exception:
session.abort()
else:
session.commit()
finally:
session.close()
request.add_finished_callback(cleanup)
return session
config.add_request_method(get_pony_session, 'pony_session', reify=True)
您可以查看金字塔如何使用 pyramid_tm 补间和炼金术 cookiecutter,因为它确实是解决此问题的最佳方法。如果你愿意,你甚至可以写一个小的包装器来将小马的会话挂接到 pyramid_tm 中。为此,您基本上编写了一个数据管理器 [1, 2] 来管理小马会话并加入 pyramid_tm 事务(此事务是 "virtual" 并且与任何特定数据库无关)和一个请求 属性:
class PonySessionManager:
def __init__(self, session):
self.session = session
def tpc_abort(self, txn):
self.session.abort()
def tpc_commit(self, txn):
self.session.commit()
def tpc_finish(self, txn):
self.session.close()
def get_pony_session(request):
session = ... # load a pony session somehow
manager = PonySessionManager(session)
# join the manager to the pyramid_tm transaction via join()
txn = request.tm.get()
txn.join(manager)
return manager
config.add_request_method(get_pony_session, 'pony_session', reify=True)
请注意,数据管理器比要求的要简单一些,但并不难。
一天结束时,您可能会发现下图 [2] 有助于理解金字塔以及您可以使用哪些挂钩。很少有人只想包装视图本身而不是更多的管道。
[1] http://zodb.readthedocs.io/en/latest/transactions.html
[2] http://transaction.readthedocs.io/en/latest/datamanager.html
[3]http://docs.pylonsproject.org/projects/pyramid/en/1.8-branch/narr/router.html
以下代码抛出 DatabaseSessionIsOver
异常,如 this post 中所述:
@view_config(route_name='home', renderer='templates/home.jinja2')
@orm.db_session()
def home(self):
x = models.Entity(...)
return {'x': x}
我使用 return render_to_response('templates/home.jinja2', {'x': x})
解决了这个问题,它是上面提到的 post 中建议的 render_template()
的金字塔等价物。
一切正常,但我认为有更好的解决方案:我认为我应该让 Pyramid 管理 Pony 会话。
可能吗?
我该怎么做?
您的问题是您要从视图返回托管对象 x
,然后在呈现视图的响应之前关闭 orm 会话。您希望会话包装请求生命周期的大部分,以便您的托管对象保持更长的生命周期。对于数据库会话之类的东西,补间确实是处理此问题的最佳方法,但还有其他一些方法,例如请求 属性 request.pony_session
和可以关闭会话的完成回调的组合.例如(对不起,我实际上不知道小马的 api 所以你必须填写实际的方法):
def get_pony_session(request):
session = ... # load a pony session somehow
def cleanup(request):
try:
if request.exception:
session.abort()
else:
session.commit()
finally:
session.close()
request.add_finished_callback(cleanup)
return session
config.add_request_method(get_pony_session, 'pony_session', reify=True)
您可以查看金字塔如何使用 pyramid_tm 补间和炼金术 cookiecutter,因为它确实是解决此问题的最佳方法。如果你愿意,你甚至可以写一个小的包装器来将小马的会话挂接到 pyramid_tm 中。为此,您基本上编写了一个数据管理器 [1, 2] 来管理小马会话并加入 pyramid_tm 事务(此事务是 "virtual" 并且与任何特定数据库无关)和一个请求 属性:
class PonySessionManager:
def __init__(self, session):
self.session = session
def tpc_abort(self, txn):
self.session.abort()
def tpc_commit(self, txn):
self.session.commit()
def tpc_finish(self, txn):
self.session.close()
def get_pony_session(request):
session = ... # load a pony session somehow
manager = PonySessionManager(session)
# join the manager to the pyramid_tm transaction via join()
txn = request.tm.get()
txn.join(manager)
return manager
config.add_request_method(get_pony_session, 'pony_session', reify=True)
请注意,数据管理器比要求的要简单一些,但并不难。
一天结束时,您可能会发现下图 [2] 有助于理解金字塔以及您可以使用哪些挂钩。很少有人只想包装视图本身而不是更多的管道。
[1] http://zodb.readthedocs.io/en/latest/transactions.html
[2] http://transaction.readthedocs.io/en/latest/datamanager.html
[3]http://docs.pylonsproject.org/projects/pyramid/en/1.8-branch/narr/router.html