【问题标题】:How to delete a table in SQLAlchemy?如何删除 SQLAlchemy 中的表?
【发布时间】:2016-06-25 10:08:13
【问题描述】:

我想使用 SQLAlchemy 删除一个表。

由于我一遍又一遍地测试,我想删除表my_users,这样我每次都可以从头开始。

到目前为止,我正在使用 SQLAlchemy 通过 engine.execute() 方法执行原始 SQL:

sql = text('DROP TABLE IF EXISTS my_users;')
result = engine.execute(sql)

但是,我想知道是否有一些标准方法可以做到这一点。我能找到的唯一一个是drop_all(),但它会删除所有结构,而不仅仅是一个特定的表:

Base.metadata.drop_all(engine)   # all tables are deleted

例如,给出这个非常基本的例子。它包含一个 SQLite 基础架构,其中包含一个表 my_users,我在其中添加了一些内容。

from sqlalchemy import create_engine, Column, Integer, String, text
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite://', echo=False)
Base = declarative_base()

class User(Base):
    __tablename__ = "my_users"

    id = Column(Integer, primary_key=True)
    name = Column(String)

    def __init__(self, name):
        self.name = name

# Create all the tables in the database which are
# defined by Base's subclasses such as User
Base.metadata.create_all(engine)

# Construct a sessionmaker factory object
session = sessionmaker()

# Bind the sessionmaker to engine
session.configure(bind=engine)

# Generate a session to work with
s = session()

# Add some content
s.add(User('myname'))
s.commit()

# Fetch the data
print(s.query(User).filter(User.name == 'myname').one().name)

对于这种特定情况,drop_all() 会起作用,但从我开始拥有多个桌子并且我想保留其他桌子的那一刻起,它就不方便了。

【问题讨论】:

  • 注意:必须在 text(...) 中包围 sql 查询才能正常工作。如果省略,则 SQLAlchemy 不起作用,并且它不会提供任何关于它为什么不起作用的反馈。

标签: python sqlite sqlalchemy drop-table


【解决方案1】:

只需针对表格对象调用drop()。 来自the docs

为此表发出 DROP 语句,使用给定的 Connectable 进行连接。

在你的情况下应该是:

User.__table__.drop()

如果您遇到如下异常:

sqlalchemy.exc.UnboundExecutionError: Table object 'my_users' is not bound to an Engine or Connection. Execution can not proceed without a database to execute against

你需要通过引擎:

User.__table__.drop(engine)

【讨论】:

  • 这仅在表存在的情况下有效,如果您删除整个 .db 文件并想再次创建它,则会出错。我对此提出了后续问题,如果您愿意,请查看:stackoverflow.com/questions/39493174/…
  • 这不能在事务中使用。如果表被删除,我想回滚事务,但其他查询(如再次创建它们)会引发异常。有了这个我就做不到了。
  • @KarinaKlinkevičiūtė 您可以先检查该表是否(不)存在;例如engine = db.engine; if not engine.dialect.has_table(engine, ModelClass.__tablename__): ModelClass.__table__.create(engine)
  • 访问 db = SQLAlchemy(app) 然后执行 User.__table__.drop(db.engine) 对我有用
  • 是否没有公开的 API,而不是使用私有的 __table__ 属性?
【解决方案2】:

除了调用cls.__table__.drop(your_engine),你可以试试这个:

Base.metadata.drop_all(bind=your_engine, tables=[User.__table__])

这个方法和create_all() 方法一样接受一个可选参数tables,它接受一个sqlalchemy.sql.schema.Table 实例的迭代器。

您可以通过这种方式控制要创建或删除哪些表。

【讨论】:

  • 对我来说,这个答案在语义上更清晰。创建或删除表更多的是与数据库级别相关,因此最好处理 Base 而不是映射类。或许 SqlAlchemy 在后台做了同样的事情。
  • +1 这个答案是最简洁的,也是提到 create_all() 方法的另一个荣誉。在这个时间点,这应该是公认的答案,我希望 sqlalchemy 团队在他们的文档中添加这个 sn-p。
【解决方案3】:

对于没有访问表类的特殊情况,只需要按表名删除表,然后使用此代码

import logging
from sqlalchemy import MetaData
from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.declarative import declarative_base

DATABASE = {
   'drivername': 'sqlite',
   # 'host': 'localhost',
   # 'port': '5432',
   # 'username': 'YOUR_USERNAME',
   # 'password': 'YOUR_PASSWORD',
   'database': '/path/to/your_db.sqlite'
}

def drop_table(table_name):
   engine = create_engine(URL(**DATABASE))
   base = declarative_base()
   metadata = MetaData(engine, reflect=True)
   table = metadata.tables.get(table_name)
   if table is not None:
       logging.info(f'Deleting {table_name} table')
       base.metadata.drop_all(engine, [table], checkfirst=True)

drop_table('users')

【讨论】:

  • 对此表示非常感谢。我一直在寻找这种删除表的方法,但没有成功。你的建议正是我所需要的。
  • note a new answer 被张贴提及 MetaData(engine, reflect=True) 的弃用。
【解决方案4】:

以下是您可以在 iPython 中执行以测试 Postgres 上表的创建和删除的示例代码

from sqlalchemy import * # imports all needed modules from sqlalchemy

engine = create_engine('postgresql://python:python@127.0.0.1/production') # connection properties stored

metadata = MetaData() # stores the 'production' database's metadata

users = Table('users', metadata,
Column('user_id', Integer),
Column('first_name', String(150)),
Column('last_name', String(150)),
Column('email', String(255)),
schema='python') # defines the 'users' table structure in the 'python' schema of our connection to the 'production' db

users.create(engine) # creates the users table

users.drop(engine) # drops the users table

您还可以使用相同的示例和屏幕截图预览我在 Wordpress 上的文章:oscarvalles.wordpress.com(搜索 SQL Alchemy)。

【讨论】:

    【解决方案5】:

    这是@Levon 答案的更新,因为MetaData(engine, reflect=True) 现在已弃用。如果您无权访问表类或想按表名删除表,这很有用。

    from sqlalchemy import MetaData
    from sqlalchemy import create_engine
    from sqlalchemy.engine.url import URL
    from sqlalchemy.ext.declarative import declarative_base
    
    DATABASE = {
       'drivername': 'sqlite',
       # 'host': 'localhost',
       # 'port': '5432',
       # 'username': 'YOUR_USERNAME',
       # 'password': 'YOUR_PASSWORD',
       'database': '/path/to/your_db.sqlite'
    }
    
    engine = create_engine(URL(**DATABASE))
    
    def drop_table(table_name, engine=engine):
        Base = declarative_base()
        metadata = MetaData()
        metadata.reflect(bind=engine)
        table = metadata.tables[table_name]
        if table is not None:
            Base.metadata.drop_all(engine, [table], checkfirst=True)
    
    drop_table('users')
    

    否则,您可能更喜欢使用cls.__table__.drop(engine)cls.__table__.create(engine),例如

    User.__table__.drop(engine)
    User.__table__.create(engine)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-13
      • 1970-01-01
      • 2012-01-29
      • 2018-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多