The following code throws a DatabaseSessionIsOver
exception, as described in this post:
@view_config(route_name='home', renderer='templates/home.jinja2')
@orm.db_session()
def home(self):
x = models.Entity(...)
return {'x': x}
I solved the problem using return render_to_response('templates/home.jinja2', {'x': x})
, which is the Pyramid equivalent of the render_template()
suggested in the post mentioned above.
Everything works well, but I think there is a better solution: I think I should tell Pyramid to manage the Pony session.
Is it possible?
How do I do it?
Your issue is that you're returning managed object x
from the view and then the orm session is closed before the view's response is rendered. You want the session to wrap a larger portion of the request lifecycle so that your managed objects stay alive longer. For something like a database session a tween is really the best way to handle this but there are some other ways as well such as a combination of a request property request.pony_session
and a finished callback that can close the session. For example (sorry I don't actually know pony's api so you have to fill in the actual methods):
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)
You can look at how pyramid does things with the pyramid_tm tween and the alchemy cookiecutter as it really is the best approach for this problem. You could even write a small wrapper to hook pony's session into pyramid_tm if you wanted. To do this you basically write a data manager [1, 2] that manages the pony session and joins to the pyramid_tm transaction (this transaction is "virtual" and has nothing to do with any particular database) and a request property:
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)
Note that data manager is a little more simplistic than what is required but it's not difficult.
At the end of the day you will probably find the following diagram [2] helpful to understand pyramid and what hooks you can use. It is rare that you only want to wrap the view itself and not more of the pipeline.
[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