SQLAlchemy + Tornado: Как создать область действия для ScopedSession SQLAlchemy? - PullRequest
6 голосов
/ 30 декабря 2011

Используя торнадо, я хочу создать немного магии промежуточного программного обеспечения, которая гарантирует, что мои сеансы SQLAlchemy будут правильно закрыты / очищены, чтобы объекты не передавались из одного запроса в другой.Хитрость заключается в том, что, поскольку некоторые из моих обработчиков торнадо являются асинхронными, я не могу просто поделиться одним сеансом для каждого запроса.

Так что мне остается пытаться создать ScopedSession, который знает, как создать новый сеанс длякаждый запрос.Все, что мне нужно сделать, это определить область действия для моего кода, которая может превратить текущий выполняемый запрос в какой-то уникальный ключ, однако я не могу понять, как получить текущий запрос в любомодин момент времени (вне области действия текущего RequestHandler, к которому у моей функции тоже нет доступа).

Есть ли что-то, что я могу сделать, чтобы эта работа работала?

Ответы [ 2 ]

4 голосов
/ 03 января 2012

Возможно, вы захотите связать Session с самим запросом (т. Е. Не использовать scopedsession, если это не удобно).Тогда вы можете просто сказать, request.session.Все еще нужно иметь зацепки в начале / конце для настройки / разрыва.

edit: пользовательская функция определения объема

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 голосов
/ 22 декабря 2017

(Это ответ 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 Alchemy внутри declarative_base (который я бы рассматривал как анти-шаблон, так как онсвязывает модель с приложением), у Амит Матани есть нерабочий пример здесь .

...