2011-12-30 1 views
6

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

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

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

+2

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

+0

@zzzeek Если вы опубликуете это как ответ, я помету его как правильно! Чем больше я думал об этом, тем больше я понял, что вы правы - это самый быстрый и простой способ понять, что мне нужно. Благодаря! –

+0

Я тоже думал, что сеанс, созданный с помощью scopped_session между всеми обработчиками async, создаст несогласованность, не так ли? Скажем в одном обработчике, я могу вызвать scopped_session.remove() в конце обработчика, но другой обработчик (который работает асинхронно) может все еще использовать его! – giga

ответ

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

Итак, в основном мне нужно будет создать сеанс в начале запроса и назначить его обработчику запроса. но мне нужно вызвать много методов, которым нужен сеанс, мне нужно передать либо обработчик запроса, либо сам сеанс между ними ... код становится уродливым :( – giga

+0

, затем используйте scopedsession с пользовательской функцией определения области видимости. – zzzeek

+0

Можете ли вы объяснить больше о том, как написать пользовательскую функцию определения области ... спасибо. Я новичок в Python – giga

0

(Это +2017 ответ на вопрос 2011) Как @Stefano Борини отметил, самый простой способ в Торнадо 4, просто дайте RequestHandler неявно pass the session around. Торнадо будет отслеживать состояние экземпляра обработчика при использовании сопрограмм моделей декоратора:

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

Смежные вопросы