【问题标题】:How to delete multiple tables in SQLAlchemy如何在 SQLAlchemy 中删除多个表
【发布时间】:2021-08-20 14:09:15
【问题描述】:

受这个问题的启发:How to delete a table in SQLAlchemy?,我最终得到了一个问题:如何删除多个表。

假设我有 3 个表,如下所示,我想删除 2 个表(想象更多表,因此无需手动删除表)。

表格

import sqlalchemy as sqla
import sqlalchemy.ext.declarative as sqld
import sqlalchemy.orm as sqlo

sqla_base = sqld.declarative_base()

class name(sqla_base):
    __tablename__ = 'name'
    id = sqla.Column(sqla.Integer, primary_key=True)
    name = sqla.Column(sqla.String)

class job(sqla_base):
    __tablename__ = 'job'
    id = sqla.Column(sqla.Integer, primary_key=True)
    group = sqla.Column(sqla.String)

class company(sqla_base):
    __tablename__ = 'company'
    id = sqla.Column(sqla.Integer, primary_key=True)
    company = sqla.Column(sqla.String)

engine = sqla.create_engine("sqlite:///test.db", echo=True)
sqla_base.metadata.bind = engine

# Tables I want to delete
to_delete = ['job', 'function']

# Get all tables in the database
for table in engine.table_names():
    # Delete only the tables in the delete list
    if table in to_delete:
        sql = sqla.text("DROP TABLE IF EXISTS {}".format(table))
        engine.execute(sql)

# Making new tables now the old ones are deleted
sqla_base.metadata.create_all(engine)

如何在 SQLAlchemy 中使用?编辑

这可行,但是我想知道是否可以在 SQLAlchemy 样式中执行相同的操作,而不是使用 sqla.text("DROP TABLE IF EXISTS {}".format(table)) 执行原始 SQL 代码(不使用 sqla_base.metadata.drop_all(),因为这会删除所有表)。

我知道函数 tablename.__table__.drop()tablename.__table__.drop(engine) 存在,但我不想为每个表手动键入它。

根据@daveoncode 给出的答案,以下代码可以满足我的要求(编辑2:添加checkfirst=True,以防它在db 和str() 中尚不存在):

for table in sqla_base.metadata.sorted_tables:
    if str(table) in self.to_delete:
        table.drop(checkfirst=True)

问题

如何以 SQLAlchemy 样式删除多个表,实现与上面的原始 SQL 代码相同的效果?

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    你得到的错误非常清楚:

    AttributeError: 'str' object has no attribute '__table__'
    

    你不是在表对象上迭代,而是在表名上迭代(又名字符串!),所以字符串当然没有属性__table__,所以你的声明:

    tablename.__table__.drop() or tablename.__table__.drop(engine)
    

    错了!应该是:

    table_instance.__table__.drop() or table_instance.__table__.drop(engine)
    

    您可以从元数据访问表实例。看这里:

    http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.MetaData.sorted_tables

    更新:

    无论如何drop_all() 是在一个简单命令中删除所有表的方法:http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.MetaData.drop_all

    【讨论】:

    • 我知道为什么我的示例代码不起作用,我只是把它放在那里以显示我的推理路线。例如,我也尝试过:for table in sqla_base.metadata.tables:,但这也返回了一个字符串。根据您的建议:for table in sqla_base.metadata.sorted_tables: 有效 :) 我没想到它会起作用,因为只是 .tables 返回了一个字符串,那么为什么 .sorted_tables 会返回一个 table_instance? (而且我不需要对其进行排序)。
    • 您应该始终使用 sorted_tables,因为这样您就可以按照依赖关系的顺序正确删除它们...无论如何使用 drop_all()(阅读我更新的答案);)
    • 我想避免使用drop_all,因为我的意图是只删除某些表。我更新了我的问题(请参阅编辑)以包含使用您的 sorted_tables 获得的工作代码。谢谢。
    【解决方案2】:

    正如 WeiHao 在https://stackoverflow.com/a/49644099/5892421 中回答的那样:
    drop_all 接受一个可选参数tables,指示要删除的表

    to_deletes = [
       job.__table__,
       company.__table__,
    ]
    Base.metadata.drop_all(bind=your_engine, tables=to_deletes)
    # create tables
    Base.metadata.create_all(bind=your_engine, tables=to_deletes)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      • 2011-09-03
      • 2021-08-13
      • 1970-01-01
      相关资源
      最近更新 更多