Postgresql 使用SQLAlchemy和Alembic检查数据库中是否存在表列

Postgresql 使用SQLAlchemy和Alembic检查数据库中是否存在表列,postgresql,sqlalchemy,alembic,Postgresql,Sqlalchemy,Alembic,我使用Alembic作为迁移工具,并在已经更新的数据库上启动以下伪脚本(Alembic没有修订条目,数据库模式只是最新的) revision='1067fd2d11c8' 向下修订=无 从alembic导入op 将sqlalchemy作为sa导入 def升级(): op.add_列('box',sa.column('has_data',sa.Boolean,server_default='0')) def降级(): 通过 只有在PostgreSQL落后的情况下,才会出现以下错误(MySQL都很

我使用Alembic作为迁移工具,并在已经更新的数据库上启动以下伪脚本(Alembic没有修订条目,数据库模式只是最新的)

revision='1067fd2d11c8'
向下修订=无
从alembic导入op
将sqlalchemy作为sa导入
def升级():
op.add_列('box',sa.column('has_data',sa.Boolean,server_default='0'))
def降级():
通过
只有在PostgreSQL落后的情况下,才会出现以下错误(MySQL都很好):

最后一行表示列
的数据已经存在


我想检查该列是否存在于
op.add\u column

之前。最简单的答案是不要尝试这样做。相反,让Alembic迁移代表数据库的完整布局。然后,您所做的任何迁移都将基于对现有数据库的更改

若要在已有数据库的情况下开始迁移,请临时指向空数据库并运行
alembic revision--autogenerate-m“base”
。然后,指向实际数据库并运行
alembic stamp head
,表示数据库的当前状态由最新的迁移表示,而不是实际运行它


如果出于某种原因不想这样做,您可以选择不使用
--autogenerate
,而是生成空的修订版,用所需的操作填充。Alembic不会阻止您这样做,它只是不太方便。

不幸的是,在这种情况下,我们有多个具有不同模式的版本,所有这些版本都需要迁移到单个代码库。任何地方都还没有迁移,任何数据库中都没有标记版本。因此,第一次迁移将有这些条件检查。在第一次迁移之后,一切都将处于已知状态,我可以避免此类黑客攻击

因此,我在迁移中添加了这个(信用属于):

我的升级功能有以下检查(请注意,我有一个批标记集,用于添加带有op.batch\u alter\u table的
行,这可能在大多数设置中都不存在:

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('mytable', schema=None) as batch_op:
        if not _table_has_column('mytable', 'mycol'):
            batch_op.add_column(sa.Column('mycol', sa.Integer(), nullable=True))
        if not _table_has_column('mytable', 'mycol2'):
            batch_op.add_column(sa.Column('mycol2', sa.Integer(), nullable=True))
from alembic import op
from sqlalchemy import engine_from_config
from sqlalchemy.engine import reflection

def _table_has_column(table, column):
    config = op.get_context().config
    engine = engine_from_config(
        config.get_section(config.config_ini_section), prefix='sqlalchemy.')
    insp = reflection.Inspector.from_engine(engine)
    has_column = False
    for col in insp.get_columns(table):
        if column not in col['name']:
            continue
        has_column = True
    return has_column
def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('mytable', schema=None) as batch_op:
        if not _table_has_column('mytable', 'mycol'):
            batch_op.add_column(sa.Column('mycol', sa.Integer(), nullable=True))
        if not _table_has_column('mytable', 'mycol2'):
            batch_op.add_column(sa.Column('mycol2', sa.Integer(), nullable=True))