2013-02-10 10 views
11

Ho un'applicazione python con molte funzioni di accesso al database, utilizzando sqlalchemy. Sto cercando di evitare di avere un sacco di codice di gestione delle sessioni di codice in merito a queste funzioni.Evitare il codice di gestione della sessione di codice in sqlalchemy

devo numerose funzioni che sembrano qualcosa di simile:

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() 

sto cercando di refactoring queste funzioni, ma non sono sicuro che avere il miglior approccio ancora. Il migliore che attualmente ho è il seguente:

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) 

Esiste un modo migliore o più idiomatico per farlo? Forse usando un decoratore?

Grazie, suggerimento Jon

+1

Un 'context manager' sarebbe un ottimo modo per andare. –

risposta

0

di morphyn utilizzare un gestore di contesto è buono. È possibile creare tale gestore di contesto applicando il decoratore contextlib.contextmanager a una funzione molto simile alla prima get_ticket_history, sostituendo il codice tra try e tranne con una dichiarazione yield e rinominandola, ad esempio, transaction. PEP 343 ha un esempio quasi identico di quel nome.

Quindi, utilizzare tale gestore di contesto con l'istruzione with per reimplementare get_ticket_history. Sembra SQLAlchemy prevede già che la funzione, anche se, come metodo di begin:

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

14

La documentazione SQLAlchemy presentano un possibile modo di fare questo con il contesto manager.

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

copia il frammento di codice per completezza:

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() 

Questo session_scope può essere utilizzato in modo pulito senza ripetere la piastra caldaia ora.

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

Gli sviluppatori di SQLAlchemy documentano una possibile, probabile e semplice implementazione che risolve bene il problema della durata della sessione. Perché non hanno fatto il miglio supplementare e lo hanno fornito come funzione built-in invece di avere tutti gli utenti della biblioteca riscrivere una versione di quel codice nella loro base di codice? – ereOn

+0

Buon punto, stava anche pensando la stessa cosa. –

Problemi correlati