web-dev-qa-db-fra.com

SQLAlchemy, effacez le contenu de la base de données mais ne laissez pas tomber le schéma

Je développe une application Pylons basée sur une base de données existante, donc j'utilise la réflexion. J'ai un fichier SQL avec le schéma que j'ai utilisé pour créer ma base de données de test. C'est pourquoi je ne peux pas simplement utiliser drop_all et create_all.

Je voudrais écrire quelques tests unitaires et j'ai rencontré le problème de la suppression du contenu de la base de données après chaque test. Je veux juste effacer toutes les données mais laisser les tables intactes. Est-ce possible?

L'application utilise Postgres et c'est ce qui doit également être utilisé pour les tests.

46
Juliusz Gonera

J'ai demandé la même chose sur le groupe Google SQLAlchemy, et j'ai eu une recette qui semble bien fonctionner (toutes mes tables sont vidées). Voir le fil pour référence.

Mon code (extrait) ressemble à ceci:

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: j'ai modifié le code pour supprimer les tables dans l'ordre inverse; soi-disant, cela devrait garantir que les enfants sont supprimés avant les parents.

48
aknuds1

Pour PostgreSQL utilisant 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()

Remarque: RESTART IDENTITY; garantit que toutes les séquences sont également réinitialisées. Cependant, c'est plus lent que la recette DELETE de @ aknuds1 de 50%.

Une autre recette consiste à supprimer d'abord toutes les tables, puis à les recréer. C'est plus lent de 50%:

Base.metadata.drop_all(bind=engine)
Base.metadata.create_all(bind=engine)
12
kolypto