SQLAlchemy + Tornado:如何为SQLAlchemy的ScopedSession创建scopefunc?

时间:2011-12-30 00:30:41

标签: python sqlalchemy tornado

使用龙卷风,我想创建一些中间件魔法,以确保我的SQLAlchemy会话得到正确关闭/清理,以便不会将对象从一个请求共享到下一个请求。诀窍是,由于我的一些龙卷风处理程序是异步的,我不能只为每个请求共享一个会话。

所以我试图创建一个知道如何为每个请求创建一个新会话的ScopedSession。我需要做的就是为我的代码定义一个scopefunc,它可以将当前正在执行的请求转换为某种类型的唯一键,但是我似乎无法弄清楚如何获取当前请求任何一个时间点(当前RequestHandler范围之外,我的函数无权访问)。

我能做些什么来使这项工作?

2 个答案:

答案 0 :(得分:4)

您可能希望将Session与请求本身相关联(即如果不方便,请不要使用scopedsession)。然后你可以说,request.session。仍然需要在开始/结束处设置钩子以进行设置/拆卸。

编辑:自定义范围函数

def get_current_tornado_request():
   # TODO: ask on the Tornado mailing list how
   # to acquire the request currently being invoked

Session = scoped_session(sessionmaker(), scopefunc=get_current_tornado_request)

答案 1 :(得分:0)

(这是2017年问题的2017年答案)正如@Stefano Borini所指出的,Tornado 4中最简单的方法就是让RequestHandler隐式pass the session around。使用协程装饰器模式时,Tornado将跟踪处理程序实例状态:

import logging

_logger = logging.getLogger(__name__)

from sqlalchemy import create_engine, exc as sqla_exc
from sqlalchemy.orm import sessionmaker, exc as orm_exc

from tornado import gen
from tornado.web import RequestHandler

from my_models import SQLA_Class

Session = sessionmaker(bind=create_engine(...))

class BaseHandler(RequestHandler):

    @gen.coroutine
    def prepare():
        self.db_session = Session()

    def on_finish():
        self.db_session.close()

class MyHander(BaseHandler):

    @gen.coroutine
    def post():
        SQLA_Object = self.db_session.query(SQLA_Class)...
        SQLA_Object.attribute = ...

        try:
            db_session.commit()
        except sqla_exc.SQLAlchemyError:
            _logger.exception("Couldn't commit")
            db_session.rollback()

如果你真的需要异步引用declarative_base内的SQL Alchemy会话(我认为这是反模式,因为它将模型过度耦合到应用程序),Amit Matani有一个不工作的例如here