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

问题描述 投票:6回答:2

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

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

有什么我可以做的工作吗?

python sqlalchemy tornado
2个回答
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)

0
投票

(这是对2011年问题的2017年答案)正如@Stefano Borini所指出的,在Tornado 4中最简单的方法就是让RequestHandler隐含地使用pass the session around。使用coroutine装饰器模式时,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

© www.soinside.com 2019 - 2024. All rights reserved.