【问题标题】:Prevent alembic from autogenerating tables防止 alembic 自动生成表
【发布时间】:2019-03-10 17:59:57
【问题描述】:

我是 so alembic 的新手,所以我可能会错过它的概念,但这是问题所在。

我在这样的烧瓶应用中有一些 sqlalchemy 表:

class Data(Base):
__tablename__ = 'Data'
__table_args__ = {'schema': 'schema'}
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)

我初始化我的表:

Base = declarative_base()
engine = create_engine(db_link, pool_size=100, max_overflow=0)
Base.metadata.create_all(engine)
Session = sessionmaker()
Session.configure(bind=engine)

到那时,我在我的数据库中手动创建了表,并且一切正常。 为了以后让我的项目富有成效,我希望能够使用 alembic 迁移我的数据库。因为我将使用的一些表(在不同的模式中)是只读的并且是由另一个程序创建的,所以我只想迁移一些 sqlalchemy 表。因此我的升级脚本看起来像(由 alembic revision --autogenerate 创建):

revision = 'bb1d39b7eee1'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('Data',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(), nullable=False),
    sa.PrimaryKeyConstraint('id'),
    schema='schema'
    )
    ...

当我现在使用空数据库将架构迁移到时:

alembic upgrade head

我收到以下错误:

sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('42S01', "[42S01] [M
icrosoft][SQL Server Native Client 11.0][SQL Server]There is already an object n
amed 'Data' in the database. (2714) (SQLExecDirectW)") [SQL: '\nCREATE TABLE schema.
[Data] (\n\tid INTEGER NOT NULL IDENTITY(1,1), \n\tname VARCHAR(max) NOT NULL, \
 \n\tPRIMARY KEY (id), \n\tCHECK (IN (0, 1))\n)\n\n']

看起来 alembic 会自动创建所有表,然后再次尝试在我的修订脚本中创建这些表。如果那是真的,我怎么能告诉 alembic 不要自动创建任何表而只运行我创建的脚本?

【问题讨论】:

  • 你已经在数据库上创建了多少张表?如果数量较少,您可以通读自动生成的 alembic 迁移脚本并删除已创建的 create_table 条目。然后运行升级
  • 在哪里可以找到该脚本?您是在谈论修订脚本(在版本文件夹中)吗?我的问题是,alembic 在运行该脚本之前会创建我在 sqlalchemy 中拥有的所有表。
  • 即使我尝试在新创建的完全空的数据库上运行升级头,我也得到了“试图从问题中创建所有已存在的表错误”

标签: python flask sqlalchemy alembic


【解决方案1】:

您的迁移显式创建Data 表:

def upgrade():
    ...
    op.create_table('Data',
    ...

所以如果您的Data 表已经存在,因为您已经手动创建了它,那么出现错误是正常的。

编辑: 我不确定它何时执行,但您可能想尝试在数据库初始化脚本中注释 Base.metadata.create_all(engine) 行。我怀疑它是为了创建表格。 在运行迁移之前我从未见过 alembic 创建表(这是创建表的迁移工作),如果它不能解决您的问题,我认为问题不是来自 alembic。


Alembic 旨在从一开始就管理您的数据库迁移,它不假定您已经创建了表。

基本上,它会创建一个表来保存应用于数据库的迁移历史记录。当您运行第一次升级时,还没有应用迁移,因此 Alembic 将尝试运行从根目录(其down_revisionNone)到头目录的所有迁移升级。 在每次应用迁移时,它还会更新其历史记录表以反映数据库状态。

您可以(按我的偏好级别排序):

  1. 删除现有的表并让 alembic 创建它们。这样,Alembic 只需按照迁移中声明的方式创建表并更新其历史记录。

  2. 让 Alembic 相信它已经通过手动填充其历史记录表应用了第一次迁移(我从未这样做过,但我认为这是可能的)。这样它就不会再次尝试应用它了

  3. 从根迁移的 upgrade() 函数中删除 create_table 指令(也可能从 downgrade() 函数中删除 drop_table)。这样,Alembic 将运行迁移而不尝试创建已经存在的表,它应该可以工作。它还将记录迁移应用到自己的历史记录中。

  4. 在您的迁移中添加一个测试以仅在该表尚不存在时创建该表,但在这种情况下您将如何管理降级?

【讨论】:

  • 我的问题是我想控制 alembic 的功能。因此,我希望我的第一个修订版能够创建我想要的表(op.create_table)。即使我在一个新的空数据库上运行我的 alembic 升级脚本,我也会收到此错误。这使我得出的结论是,在这些修订脚本运行之前,我激活了一些 alembic 选项,它创建了我拥有的所有 sqlalchemy 表,独立于我的修订脚本。
  • 谢谢,Base.metadata.create_all(engine) 是问题所在。当我运行脚本时,它是否在没有 alembic 的情况下创建了我的表? Stackoverflow 告诉我,我需要等待 15 小时才能获得赏金,所以如果我忘记了,明天请随时记住我 ;-)
  • @Tryph 感谢您在编辑部分的建议(评论 Base.metadata.create_all(engine) 行)。
猜你喜欢
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 2020-11-05
  • 2015-08-06
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 2013-06-15
相关资源
最近更新 更多