2011-01-21 8 views
38

Estoy desarrollando una aplicación Pylons que se basa en la existencia de una base de datos, así que estoy usando el reflejo. Tengo un archivo SQL con el esquema que utilicé para crear mi base de datos de prueba. Es por eso que no puedo simplemente usar drop_all y create_all.SQLAlchemy, borre el contenido de la base de datos, pero no descarte el esquema

Me gustaría escribir algunas pruebas de unidad y me enfrenté al problema de borrar el contenido de la base de datos después de cada prueba. Solo quiero borrar todos los datos pero dejar las tablas intactas. es posible?

La aplicación utiliza Postgres y esto es lo que se debe usar también para las pruebas.

+0

Debe usar las transacciones. http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#joining-a-session-into-anternalextransaction – charlax

Respuesta

40

Pregunté por lo mismo en el grupo SQLAlchemy de Google, y obtuve una receta que parece funcionar bien (todas mis tablas están vacías). Ver the thread para referencia.

Mi código (extracto) se ve así:

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

Edición: He modificado el código para eliminar tablas en el orden inverso; supuestamente esto debería asegurar que los niños sean eliminados antes que los padres.

+4

¡Parece que funciona! Gracias. El código exacto que uso en Pylons es: 'para la tabla en reversa (meta.Base.metadata.sorted_tables): meta.Session.execute (table.delete()); meta.Session.commit() ' –

+5

¿De dónde viene' engine'? Y 'contextlib'? ¿Es la biblioteca estándar? Esta respuesta sería mejor si las importaciones estuvieran completas. – Zelphir

0

Cómo sobre el uso truncado:

TRUNCATE [TABLA] nombre [...]

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

Esto eliminará todos los registros de la tabla, pero deje el esquema en tacto.

+1

Esto estaría bien, pero ¿cómo puedo usarlo en SQLAlchemy? 'para la tabla en meta.Base.metadata.tables.keys(): meta.Session.execute ('truncate% s'% table); meta.Session.commit() 'causa tal mensaje de error:" InternalError: (InternalError) la transacción actual se cancela, los comandos se ignoran hasta el final del bloque de transacción 'truncar data.subkeywords' {} " –

+1

Lo arreglé haciendo' truncate% s cascada, pero es dolorosamente lento. Demasiado lento para ejecutarlo después de cada prueba de unidad ... –

+2

La pregunta es para sqlalchemy, no sql. – lnhubbell

7

Para 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; asegura que todas las secuencias se restablecen también. Sin embargo, esto es más lento que la receta DELETE de @ aknuds1 en un 50%.

Otra receta es soltar todas las tablas primero y luego volver a crearlas. Esto es más lento en otro 50%:

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

'metadata.Base.metadata.drop_all (bind = engine)' da el error 'AttributeError: 'MetaData' objeto no tiene atributo 'Base' – danio

Cuestiones relacionadas