【问题标题】:Order of Alembic's autogenerated revision fileAlembic 自动生成的修订文件的顺序
【发布时间】:2020-11-17 21:16:58
【问题描述】:

我有一个非常复杂的数据库架构,我希望使用 Alembic 对其进行版本控制。我正在使用declarative_base 创建我的模型,而我的env.py 看起来像:

from logging.config import fileConfig
import os
import sys
from alembic import context
from sqlalchemy import engine_from_config, pool

sys.path.append(os.getcwd())

from app import db, create_app, Base

config = context.config
fileConfig(config.config_file_name)

app = create_app()
config.set_main_option("sqlalchemy.url", app.config["SQLALCHEMY_DATABASE_URI"])

target_metadata = Base.metadata

def run_migrations_offline():
    """Run migrations in 'offline' mode.

    This configures the context with just a URL
    and not an Engine, though an Engine is acceptable
    here as well.  By skipping the Engine creation
    we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the
    script output.

    """

    url = config.get_main_option("sqlalchemy.url")
    context.configure(url=url)

    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """

    engine = engine_from_config(
        config.get_section(config.config_ini_section),
        prefix='sqlalchemy.',
        poolclass=pool.NullPool
    )
    connection = engine.connect()
    context.configure(connection=connection, target_metadata=target_metadata)

    try:
        with context.begin_transaction():
            context.run_migrations()
    finally:
        connection.close()

if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()

当我运行以下命令时:

alembic revision --autogenerate -m ''

自动生成模式:检测正确的表:

/limbus/venv/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py:1917: SAWarning: Setting backref / back_populates on relationship UserAccountVersion.version_parent to refer to viewonly relationship UserAccount.versions will be deprecated in SQLAlchemy 1.4, and will be disallowed in a future release.  viewonly relationships should not be mutated (this warning may be suppressed after 10 occurrences)
  (self, other),
/limbus/venv/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py:1917: SAWarning: Setting backref / back_populates on relationship UserAccount.versions to refer to viewonly relationship UserAccountVersion.version_parent will be deprecated in SQLAlchemy 1.4, and will be disallowed in a future release.  viewonly relationships should not be mutated (this warning may be suppressed after 10 occurrences)
  (self, other),
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'address'
INFO  [alembic.autogenerate.compare] Detected added table 'siteinformation'
INFO  [alembic.autogenerate.compare] Detected added table 'useraccount'
INFO  [alembic.autogenerate.compare] Detected added table 'useraccount_version'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_useraccount_version_end_transaction_id' on '['end_transaction_id']'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_useraccount_version_operation_type' on '['operation_type']'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_useraccount_version_transaction_id' on '['transaction_id']'
INFO  [alembic.autogenerate.compare] Detected added table 'useraccounttoken'
  Generating /limbus/migrations/versions/9aa6e8b6781c_.py ...  done

但是,当我尝试升级时 - 它抱怨用户帐户表不存在。如果我看一下自动生成的版本文件:

    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('address',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('street_address_one', sa.String(length=256), nullable=False),
    sa.Column('street_address_two', sa.String(length=256), nullable=True),
    sa.Column('city', sa.String(length=128), nullable=False),
    sa.Column('county', sa.String(length=128), nullable=True),
    sa.Column('post_code', sa.String(length=20), nullable=False),
    sa.Column('country', sa.String(length=2), nullable=False),
    sa.Column('author_id', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['author_id'], ['useraccount.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_table('siteinformation',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('miabis_id', sa.String(length=128), nullable=True),
    sa.Column('acronym', sa.String(length=64), nullable=True),
    sa.Column('name', sa.String(length=128), nullable=True),
    sa.Column('description', sa.String(length=128), nullable=True),
    sa.Column('url', sa.String(length=128), nullable=True),
    sa.Column('address_id', sa.Integer(), nullable=False),
    sa.Column('author_id', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['address_id'], ['address.id'], ),
    sa.ForeignKeyConstraint(['author_id'], ['useraccount.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_table('useraccount',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('email', sa.String(length=320), nullable=False),
    sa.Column('password_hash', sa.String(length=256), nullable=False),
    sa.Column('title', sa.Enum('MRS', 'MISS', 'MS', 'MR', 'MX', 'PROF', 'DR', name='title'), nullable=False),
    sa.Column('first_name', sa.String(length=128), nullable=False),
    sa.Column('middle_name', sa.String(length=128), nullable=True),
    sa.Column('last_name', sa.String(length=128), nullable=False),
    sa.Column('account_type', sa.Enum('ADM', 'BIO', 'PRO', 'BOT', name='accounttype'), nullable=False),
    sa.Column('access_control', sa.Enum('ADM', 'MOD', 'PRI', 'VIE', 'BOT', name='accesscontrol'), nullable=True),
    sa.Column('is_locked', sa.Boolean(), nullable=False),
    sa.Column('site_id', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['site_id'], ['siteinformation.id'], ),
    sa.PrimaryKeyConstraint('id'),
    sa.UniqueConstraint('email')
    )
    op.create_table('useraccount_version',
    sa.Column('id', sa.Integer(), autoincrement=False, nullable=False),
    sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), autoincrement=False, nullable=True),
    sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), autoincrement=False, nullable=True),
    sa.Column('email', sa.String(length=320), autoincrement=False, nullable=True),
    sa.Column('password_hash', sa.String(length=256), autoincrement=False, nullable=True),
    sa.Column('title', sa.Enum('MRS', 'MISS', 'MS', 'MR', 'MX', 'PROF', 'DR', name='title'), autoincrement=False, nullable=True),
    sa.Column('first_name', sa.String(length=128), autoincrement=False, nullable=True),
    sa.Column('middle_name', sa.String(length=128), autoincrement=False, nullable=True),
    sa.Column('last_name', sa.String(length=128), autoincrement=False, nullable=True),
    sa.Column('account_type', sa.Enum('ADM', 'BIO', 'PRO', 'BOT', name='accounttype'), autoincrement=False, nullable=True),
    sa.Column('access_control', sa.Enum('ADM', 'MOD', 'PRI', 'VIE', 'BOT', name='accesscontrol'), autoincrement=False, nullable=True),
    sa.Column('is_locked', sa.Boolean(), autoincrement=False, nullable=True),
    sa.Column('site_id', sa.Integer(), autoincrement=False, nullable=True),
    sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
    sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
    sa.Column('operation_type', sa.SmallInteger(), nullable=False),
    sa.Column('created_on_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('updated_on_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('email_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('password_hash_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('title_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('first_name_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('middle_name_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('last_name_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('account_type_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('access_control_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('is_locked_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.Column('site_id_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
    sa.PrimaryKeyConstraint('id', 'transaction_id')
    )
    op.create_index(op.f('ix_useraccount_version_end_transaction_id'), 'useraccount_version', ['end_transaction_id'], unique=False)
    op.create_index(op.f('ix_useraccount_version_operation_type'), 'useraccount_version', ['operation_type'], unique=False)
    op.create_index(op.f('ix_useraccount_version_transaction_id'), 'useraccount_version', ['transaction_id'], unique=False)
    op.create_table('useraccounttoken',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('created_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_on', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('user_id', sa.Integer(), nullable=False),
    sa.Column('token_hash', sa.String(length=256), nullable=False),
    sa.ForeignKeyConstraint(['user_id'], ['useraccount.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

看起来用户帐户是在其他类之间建立 FK 依赖之后生成的。

我已经到处搜索了,但我不知道如何解决这个问题。任何帮助将不胜感激。

最好的祝愿。

【问题讨论】:

  • 比较典型,它会生成迁移,有时顺序正确,有时不正确,因此“请调整”,您可以手动订购并升级,因此您在引用之前先创建表它。据我所知,没有解决办法

标签: python flask sqlalchemy alembic


【解决方案1】:

所以,我意识到我在 UserAccount 中有一个指向 Site.id 的 FK,这本身就是错误的 - 但如果您可以在 FK 依赖项中使用 use_alter,那么只有在创建 Sites 表后才会创建 FK 关系.

【讨论】:

    猜你喜欢
    • 2019-04-17
    • 1970-01-01
    • 2020-11-05
    • 2019-03-10
    • 2015-03-22
    • 2012-06-26
    • 2013-06-16
    • 2015-08-06
    • 1970-01-01
    相关资源
    最近更新 更多