2013-02-10 46 views
11

我有一个python应用程序,它有很多小型数据库访问函数,使用sqlalchemy。我试图避免在这些函数周围有大量的样板会话处理代码。在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

'上下文管理器'将是一个非常好的方法。 – 2013-02-10 15:58:48

回答

0

morphyn的使用上下文管理的建议是很好的。您可以通过将contextlib.contextmanager修饰器应用于与第一个get_ticket_history非常相似的功能来创建上下文管理器,将其替换为try和yield语句之间的代码,并将其重命名为transactionPEP 343有一个近似相同的例子。

然后,使用该语句管理器和with语句重新实现get_ticket_history。它看起来像的SQLAlchemy已经提供了该功能,但是,作为法begin

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

14

的SQLAlchemy的文档呈现与上下文管理这样的一个可行的办法。

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开发了一个可能的,可能的和简单的实现,很好地解决了会话的生命期问题。他们为什么不花费额外的时间,将其作为内置函数提供,而不是让所有库用户在其代码库中重写该代码的一个版本? – ereOn 2016-01-12 12:57:16

+0

好点,也在想同样的事情。 – 2017-11-20 08:58:05