2013-02-10 1 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

«Менеджер контекста» был бы очень хорошим способом. –

ответ

0

morphyn, чтобы использовать менеджер контекста хорошо. Вы можете сделать такой менеджер контекста, применив декоратор contextlib.contextmanager к функции, очень похожей на ваш первый get_ticket_history, заменив код между try и за исключением инструкции yield и переименовав ее, скажем, transaction. PEP 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

+0

Хорошая точка, тоже думал то же самое. –

Смежные вопросы