【问题标题】:SQLAlchemy, clear database content but don't drop the schemaSQLAlchemy,清除数据库内容但不删除架构
【发布时间】:2011-06-13 09:41:55
【问题描述】:

我正在开发一个基于现有数据库的 Pylons 应用程序,所以我正在使用反射。我有一个 SQL 文件,其中包含用于创建测试数据库的架构。这就是为什么我不能简单地使用drop_allcreate_all

我想写一些单元测试,每次测试后我都遇到了清除数据库内容的问题。我只想擦除所有数据但保持表格完好无损。这可能吗?

应用程序使用 Postgres,这也是测试必须使用的。

【问题讨论】:

标签: python sqlalchemy pylons


【解决方案1】:

我在 SQLAlchemy Google 小组上询问了同样的事情,我得到了一个看起来效果很好的食谱(我所有的桌子都被清空了)。参考the thread

我的代码(摘录)如下所示:

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

编辑:我修改了代码以逆序删除表;据说这应该确保在父母之前删除孩子。

【讨论】:

  • 它似乎有效!谢谢你。我在 Pylons 中使用的确切代码是:for table in reversed(meta.Base.metadata.sorted_tables): meta.Session.execute(table.delete()); meta.Session.commit()
  • engine 来自哪里?还有contextlib?它是标准库吗?如果导入完成,这个答案会更好。
  • @MatthieuRodic,我怀疑您在此处的编辑会增加读者对此答案感到困惑的风险,而不是减少它。对于之前完成 SQLAlchemy 应用程序初始设置的读者,我认为已经隐含地清楚 meta 是什么,因此编辑对他们的理解没有影响。但是对于以前从未见过 MetaData() 并且只是在别人创建的应用程序中摸索的人来说,我担心现在的答案会让他们看起来应该创建一个 new MetaData()与此代码一起使用的实例,这当然行不通。
  • 答案中出现的元数据部分不起作用。首先,创建的元对象没有在任何地方使用,我不知道如何使它工作。但是,作为一种解决方法,将 "for" 循环替换为 for table in engine.table_names(): con.execute("DROP table " + table)
  • 缺点是这种方法不适用于具有外键约束的表。
【解决方案2】:

对于 PostgreSQL 使用 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()

注意:RESTART IDENTITY; 确保所有序列也被重置。但是,这比 @aknuds1 的 DELETE 配方慢 50%。

另一个方法是先删除所有表,然后重新创建它们。这又慢了 50%:

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

【讨论】:

  • metadata.Base.metadata.drop_all(bind=engine) 给出错误AttributeError: 'MetaData' object has no attribute 'Base'
  • 但这会导致死锁
  • @danio 你在哪里找到metadata.Base?恰恰相反:Base.metadata.... :D
  • @kolypto 好问题,它是 4 年前的,所以我很难记住!但是上面对stackoverflow.com/a/5003705/12663 的评论也使用了meta.Base.metadata.sorted_tables,而你的回答并没有解释Base 的来源,所以我想我想知道你从哪里得到Base 并使用它!也许 SQLAlchemy API 在 0. 和 1. 系列之间发生了变化?
  • @danio Base 是您的模型的声明基础 :)
【解决方案3】:

如何使用截断:

TRUNCATE [ TABLE ] 名称 [, ...]

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

这将删除表中的所有记录,但保留模式。

【讨论】:

  • 这没关系,但我如何在 SQLAlchemy 中使用它? for table in meta.Base.metadata.tables.keys(): meta.Session.execute('truncate %s' % table); meta.Session.commit() 导致这样的错误消息:“InternalError: (InternalError) 当前事务被中止,命令被忽略直到事务块'truncate data.subkeywords' {}”
  • 我通过truncate %s cascade 修复了它,但它非常缓慢。每次单元测试后运行太慢...
  • 问题是要求 sqlalchemy,而不是 sql。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多