如何在SQLAlchemy中删除多个表

5

受这个问题的启发:如何在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))(不使用sqla_base.metadata.drop_all(),因为那会删除所有表)。

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

根据@daveoncode提供的答案,以下代码可以实现我的需求(编辑2:添加checkfirst=True,以防它在数据库中不存在和使用str()):

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

问题

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

2个回答

4
你得到的错误非常清晰明了:
AttributeError: 'str' object has no attribute '__table__'

您没有在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会返回一个表实例呢?(而且我不需要排序)。 - NumesSanguis
1
你应该始终使用sorted_tables,这样你就能够按依赖顺序正确删除它们... 无论如何使用drop_all()(请阅读我的更新答案);) - daveoncode
我想避免使用drop_all,因为我的意图是仅删除特定的表。我更新了我的问题(请参见编辑),包括使用您的sorted_tables获得的工作代码。谢谢。 - NumesSanguis

1

正如WeiHao在https://dev59.com/vlsV5IYBdhLWcg3wrQgp#49644099中所回答的:
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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接