Python SQLAlchemy+;Tornado:如何为SQLAlchemy创建scopefunc';什么是范围会话?

Python SQLAlchemy+;Tornado:如何为SQLAlchemy创建scopefunc';什么是范围会话?,python,sqlalchemy,tornado,Python,Sqlalchemy,Tornado,使用tornado,我想创建一点中间件魔法,确保我的SQLAlchemy会话得到正确关闭/清理,这样就不会在一个请求到下一个请求之间共享对象。诀窍在于,由于我的一些tornado处理程序是异步的,所以我不能只为每个请求共享一个会话 因此,我只能尝试创建一个ScopedSession,它知道如何为每个请求创建一个新会话。我所需要做的就是为我的代码定义一个scopefunc,它可以将当前执行的请求转换为某种类型的唯一键,但是我似乎不知道如何在任何时间点获取当前请求(在当前RequestHandler

使用tornado,我想创建一点中间件魔法,确保我的SQLAlchemy会话得到正确关闭/清理,这样就不会在一个请求到下一个请求之间共享对象。诀窍在于,由于我的一些tornado处理程序是异步的,所以我不能只为每个请求共享一个会话

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


有什么我可以做的吗?

您可能希望将
会话
与请求本身相关联(即,如果不方便,不要使用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)
(这是2017年对2011年一个问题的回答)正如@Stefano Borini所指出的,在Tornado 4中最简单的方法就是隐式地让RequestHandler。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()

如果你真的需要异步引用一个SQL炼金术会话,它是在<代码>声明基础> /COD>(我将考虑反模式,因为它将模型与应用程序过度耦合),Amit Matani有一个不起作用的示例。

我根本不知道tornado,但您可能希望将会话与请求本身关联起来(即,如果不方便,不要使用scopedsession)。然后你可以说request.session。仍然需要在安装/拆卸的开始/结束处有挂钩。@zzzeek如果您将此作为答案发布,我会将其标记为正确!我想得越多,就越意识到你是对的——这是最快、最容易理解的获得我需要的东西的方法。谢谢我也这么认为,在所有异步处理程序之间共享通过scopped_会话创建的会话会造成不一致,对吗?假设在一个处理程序中,我可以在处理程序末尾调用scopped_session.remove(),但其他处理程序(异步运行)可能仍在使用它!因此,基本上我需要做的是在请求开始时创建一个会话,并将其分配给请求处理程序。但是我需要调用许多需要会话的方法,我需要在它们之间传递请求处理程序或会话本身。。。代码变得难看:(然后将scopedsession与自定义作用域函数一起使用。您能解释一下如何编写自定义作用域函数吗…谢谢。我是PythontorAndo(或您的应用程序)的新手,需要提供一些函数,当不带参数调用时,返回正在服务的当前请求。然后将其传递给“scopefunc”。请参见上面的编辑。我不明白,为什么不能在prepare()中启动会话?