2013-02-10 6 views
11

私は、sqlalchemyを使用して、小さなデータベースアクセス関数をたくさん持っているpythonアプリケーションを持っています。私はこれらの関数の周りに定型的なセッション処理コードがたくさんあることを避けようとしています。sqlalchemy関数のボイラープレートセッション処理コードの回避

私はこのような何かを見て多くの機能があります:私は、これらの機能をリファクタリングしようとしているが、私はまだ最善のアプローチを持っていることを確認しておりません

def get_ticket_history(Session, ticket_id): 
    s = Session() 
    try: 
     rows = s.query(TicketHistory)\ 
       .filter(TicketHistory.ticket_fk==ticket_id)\ 
       .order_by(TicketHistory.id.desc()).all() 
     s.commit() 
     return rows 
    except: 
     s.rollback() 
     raise 
    finally: 
     s.close() 

を。私が現在持っている最高のものは次のとおりです:

def execute(Session, fn, *args, **kwargs): 
    s = Session() 
    try: 
     ret = fn(s, *args, **kwargs) 
     s.commit() 
     return ret 
    except: 
     s.rollback() 
     raise 
    finally: 
     s.close() 

def get_ticket_history(self, ticket_id): 
    def sql_fn(s): 
     return s.query(TicketHistory)\ 
       .filter(TicketHistory.ticket_fk==ticket_id)\ 
       .order_by(TicketHistory.id.desc()).all() 
    return execute(self.sentinel_session, sql_fn) 

これを行うには、より良い方法や慣用的な方法がありますか?おそらくデコレータを使用していますか?

おかげで、コンテキストマネージャを使用する ジョン

+1

「コンテキストマネージャー」は非常に良い方法です。 –

答えて

0

morphynの提案は良いです。最初のget_ticket_historyとよく似た関数にcontextlib.contextmanagerデコレータを適用し、tryとexceptの間のコードをyieldと置き換えて、たとえばtransactionという名前に変更することで、コンテキストマネージャを作成できます。 PEP 343には、その名前とほぼ同じ例があります。

次に、with文でコンテキストマネージャを使用して、get_ticket_historyを再実装します。

http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#autocommit-mode

14

SQLAlchemyのドキュメントは、コンテキストマネージャでこれを行うことの可能な方法を提示:SQLAlchemyのは、すでに法beginとして、しかし、その機能を提供しますように見えます。

http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it

完全性のためにここでコードスニペットをコピー:

from contextlib import contextmanager 

@contextmanager 
def session_scope(): 
    """Provide a transactional scope around a series of operations.""" 
    session = Session() 
    try: 
     yield session 
     session.commit() 
    except: 
     session.rollback() 
     raise 
    finally: 
     session.close() 

このsession_scopeについてボイラープレートを繰り返すことなくきれいに使用することができます。

class ThingOne(object): 
    def go(self, session): 
     session.query(FooBar).update({"x": 5}) 

class ThingTwo(object): 
    def go(self, session): 
     session.query(Widget).update({"q": 18}) 

def run_my_program(): 
    with session_scope() as session: 
     ThingOne().go(session) 
     ThingTwo().go(session) 
+10

SQLAlchemyのdevsは、セッションの生涯の問題をうまく解決する、可能性のある簡単な実装を文書化しています。なぜ、彼らは余分なマイルに行き、すべてのライブラリユーザーがコードベースでそのコードの1つのバージョンを書き換えるのではなく、組み込み関数として提供していませんでしたか? – ereOn

+0

良い点も、同じことを考えていた。 –

関連する問題