避免在sqlalchemy函数中使用样板会话处理代码

Jon*_*Jon 19 python session 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()
Run Code Online (Sandbox Code Playgroud)

我试图重构这些功能,但不确定我还有最好的方法.我目前最好的是以下内容:

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)
Run Code Online (Sandbox Code Playgroud)

这样做有更好或更惯用的方法吗?也许使用装饰师?

谢谢,乔恩

r.v*_*r.v 33

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-关闭,它

复制代码段以获得完整性:

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()
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

  • SQLAlchemy开发人员记录了一个可能的,可能的和简单的实现,很好地解决了会话的生命周期问题.为什么他们没有超越英里并将其作为内置函数提供,而不是让所有库用户在其代码库中重写该代码的一个版本? (29认同)

Nee*_*raj 14

从 Sql alchemy 版本 1.4 开始:会话可以用作上下文管理器,而无需使用外部辅助函数。

文档中的示例

Session = sessionmaker(engine)

with Session() as session:
    session.add(some_object)
    session.add(some_other_object)
    session.commit()
Run Code Online (Sandbox Code Playgroud)

首先,提交事务并关闭会话,可以应用以下方法。

Session = sessionmaker(engine)

with Session.begin() as session:
    session.add(some_object)
    session.add(some_other_object)
# commits transaction, closes session 
Run Code Online (Sandbox Code Playgroud)

文档: https ://docs.sqlalchemy.org/en/14/orm/session_api.html#sqlalchemy.orm.sessionmaker


Cro*_*han 0

吗啡关于使用上下文管理器的建议很好。contextlib.contextmanager您可以通过将装饰器应用到与第一个非常相似的函数来创建这样的上下文管理器get_ticket_history,用语句替换 try 和 except 之间的代码yield并将其重命名,例如,transactionPEP 343有一个与该名称几乎相同的示例。

然后,使用该上下文管理器和 with 语句来重新实现get_ticket_history. 不过,看起来 SQLAlchemy 已经提供了该功能,作为方法begin

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