2011-01-21 11 views
38

Sto sviluppando un'app Piles basata su database esistente, quindi sto utilizzando la riflessione. Ho un file SQL con lo schema che ho usato per creare il mio database di test. Ecco perché non posso semplicemente usare drop_all e create_all.SQLAlchemy, cancella il contenuto del database ma non rilasciare lo schema

Vorrei scrivere alcuni test di unità e ho affrontato il problema di cancellare il contenuto del database dopo ogni test. Voglio solo cancellare tutti i dati ma lasciare intatti i tavoli. È possibile?

L'applicazione utilizza Postgres e questo è ciò che deve essere utilizzato anche per i test.

+0

È necessario utilizzare le transazioni. http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#joining-a-session-into-an-external-transaction – charlax

risposta

40

Ho chiesto la stessa cosa sul gruppo SQLAlchemy di Google e ho ricevuto una ricetta che sembra funzionare correttamente (tutte le mie tabelle sono state svuotate). Vedere the thread come riferimento.

Il mio codice (estratto) si presenta così:

import contextlib 
from sqlalchemy import MetaData 

meta = MetaData() 

with contextlib.closing(engine.connect()) as con: 
    trans = con.begin() 
    for table in reversed(meta.sorted_tables): 
     con.execute(table.delete()) 
    trans.commit() 

Edit: ho modificato il codice per eliminare le tabelle in ordine inverso; presumibilmente questo dovrebbe garantire che i bambini vengano cancellati prima dei genitori.

+4

Sembra funzionare! Grazie. Il codice esatto che uso in Pali è: 'per la tabella invertita (meta.Base.metadata.sorted_tables): meta.Session.execute (table.delete()); meta.Session.commit() ' –

+5

Da dove proviene' engine'? E 'contextlib'? È la libreria standard? Questa risposta sarebbe migliore se le importazioni fossero complete. – Zelphir

0

ne dite di usare troncare:

TRUNCATE [TABLE] nome [...]

(http://www.postgresql.org/docs/8.4/static/sql-truncate.html)

Questo eliminerà tutti i record nella tabella, ma lasciare lo schema in tatto.

+1

Questo sarebbe OK ma come posso usarlo in SQLAlchemy? 'per la tabella in meta.Base.metadata.tables.keys(): meta.Session.execute ('truncate% s'% table); meta.Session.commit() 'provoca tale messaggio di errore:" InternalError: (InternalError) la transazione corrente viene interrotta, i comandi ignorati fino alla fine del blocco di transazione 'truncate data.subkeywords' {} " –

+1

L'ho risolto facendo' truncate% s cascade' ma è dolorosamente lento. Troppo lento per eseguirlo dopo ogni unità di test ... –

+2

La domanda è chiedere sqlalchemy, non sql. – lnhubbell

7

Per PostgreSQL usando TRUNCATE:

with contextlib.closing(engine.connect()) as con: 
    trans = con.begin() 
    con.execute('TRUNCATE {} RESTART IDENTITY;'.format(
     ','.join(table.name 
       for table in reversed(Base.metadata.sorted_tables)))) 
    trans.commit() 

Nota: RESTART IDENTITY; assicura che tutte le sequenze vengono ripristinati pure. Tuttavia, questo è più lento della ricetta DELETE da @ aknuds1 del 50%.

Un'altra ricetta è quella di eliminare tutti i tavoli prima e quindi ricrearli. Più lento del 50%:

Base.metadata.drop_all(bind=engine) 
Base.metadata.create_all(bind=engine) 
+0

'metadata.Base.metadata.drop_all (bind = engine)' fornisce l'errore 'AttributeError: 'L'oggetto' MetaData 'non ha attributo' Base'' – danio

Problemi correlati