2011-12-30 11 views
6

竜巻を使用して、SQLAlchemyセッションが適切に閉じられ、オブジェクトが1つの要求から次の要求に共有されないようにするミドルウェアの魔法を作りたいと思います。私のトルネードハンドラのいくつかは非同期なので、リクエストごとに1つのセッションを共有することはできません。SQLAlchemy + Tornado:SQLAlchemyのScopedSessionのscopefuncを作成する方法は?

私は、各要求に対して新しいセッションを作成する方法を知っているScopedSessionを作成しようとしています。私がする必要があるのは、現在実行中のリクエストをある種の一意のキーに変えることができるコードのscopefuncを定義することだけです。しかし、どのようにすればいいのか分かりません。 (現在のRequestHandlerのスコープの外で、私の関数はどちらにもアクセスできません)。

私はこの作業をするために何かできますか?

+2

竜巻はまったく分かりませんが、セッションをリクエスト自体に関連付けることができます(便利でない場合はスコープ付きセッションを使用しないでください)。あなたは単にrequest.sessionと言うことができます。セットアップ/ティアダウンには、開始/終了時にフックが必要です。 – zzzeek

+0

@zzzeekこれを回答として投稿すると、それを正しいとマークします!私はそれについてもっと考えればするほど、あなたが正しいことを実感しました - これは私が必要とするものを得る方法を理解する最も速くて簡単です。ありがとう! –

+0

私は同じ考えをしています。すべての非同期ハンドラの間でscopped_sessionを使って作成されたセッションを共有すると、矛盾が生じるでしょうか?あるハンドラで、ハンドラの最後にscopped_session.remove()を呼び出すことができますが、(非同期に実行されている)他のハンドラはまだそれを使用している可能性があります。 – giga

答えて

4

Sessionをリクエスト自体に関連付けることができます(便利でない場合は、スコープ付きセッションを使用しないでください)。それでは、ちょうど、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

次にスコープのカスタムスコープを使用する – zzzeek

+0

もっと説明できますかPythonの新機能 – giga

0

(これは、2011年問題への2017年の答えです)@Stefano Boriniが指摘したように、トルネード4で最も簡単な方法は、ただのRequestHandlerに暗黙的にpass the session aroundをさせることです。コルーチンデコレータパターン使用した場合の竜巻は、ハンドラインスタンスの状態を追跡します:あなたは本当に非同期に私はそれ以来、アンチパターンを検討するdeclarative_base(内部のSQL錬金術セッションを参照する必要がある場合

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() 

をオーバーカップルモデルをアプリケーションに変換する)、Amit Mataniは非実用例のhereを持っています。

関連する問題