2013-02-10 3 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의 제안이 좋다. contextlib.contextmanager 데코레이터를 첫 번째 get_ticket_history과 매우 비슷한 함수에 적용하고 try와 except 사이의 코드를 yield 문으로 바꾸고 이름을 바꾸면 (예 : transaction) 컨텍스트 관리자를 만들 수 있습니다. PEP 343에는 거의 동일한 이름의 예제가 있습니다.

그런 다음 with 문을 사용하여 해당 컨텍스트 관리자를 사용하여 get_ticket_history을 다시 구현하십시오. SQLAlchemy의 이미하지만, 그 기능을 제공하는 것처럼 방법 begin 것처럼 보인다 :

SQLAlchemy의 워드 프로세서

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

14

콘텍스트 관리자와이를위한 가능한 방법을 제시한다.

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는 세션의 수명 문제를 멋지게 해결할 수있는 가능성있는 간단한 구현을 문서화합니다. 왜 그들은 여분의 마일을 가지지 않고 모든 라이브러리 사용자가 코드베이스에서 해당 코드의 한 버전을 다시 작성하는 대신 기본 제공 함수로 제공하지 않았습니까? – ereOn

+0

좋은 점도 같은 생각을하고있었습니다. –