Проверьте, существует ли столбец таблицы в базе данных, используя SQLAlchemy и Alembic.

Я использую Alembic в качестве инструмента миграции и запускаю следующий псевдоскрипт в уже обновленной базе данных (нет записей ревизий для Alembic, схема базы данных только что обновлена).

revision = '1067fd2d11c8'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade():
    op.add_column('box', sa.Column('has_data', sa.Boolean, server_default='0'))


def downgrade():
    pass

Это дает мне следующую ошибку только с PostgreSQL (с MySQL все хорошо):

INFO  [alembic.migration] Context impl PostgresqlImpl.
INFO  [alembic.migration] Will assume transactional DDL.
INFO  [root] (ProgrammingError) ERREUR:  la colonne « has_data » de la relation « box » existe déjà

Последняя строка означает, что столбец has_data уже существует.

Я хочу проверить, что столбец существует до op.add_column.


person ScotchAndSoda    schedule 06.06.2014    source источник


Ответы (2)


Самый простой ответ — не пытаться это сделать. Вместо этого сделайте так, чтобы ваши миграции Alembic представляли полную структуру базы данных. Тогда любые выполненные вами миграции будут основываться на изменениях в существующей базе данных.

Чтобы начать миграцию, если у вас уже есть база данных, временно укажите на пустую базу данных и запустите alembic revision --autogenerate -m "base". Затем снова укажите на реальную базу данных и запустите alembic stamp head, чтобы сказать, что текущее состояние базы данных представлено последней миграцией, но фактически не запуская ее.

Если вы по какой-то причине не хотите этого делать, вы можете не использовать --autogenerate и вместо этого создавать пустые ревизии, которые вы заполняете нужными операциями. Alembic не помешает вам это сделать, просто это гораздо менее удобно.

person davidism    schedule 06.06.2014

К сожалению, я нахожусь в ситуации, когда у нас есть несколько версий с разными схемами, и все они должны быть перенесены на единую кодовую базу. Пока нигде нет миграций и нет версий, помеченных ни в одной базе данных. Таким образом, первая миграция будет иметь эти условные проверки. После первой миграции все будет в известном состоянии и я смогу избежать таких взломов.

Поэтому я добавил это в свою миграцию (кредит принадлежит http://www.derstappen-it.de/tech-blog/sqlalchemie-alembic-check-if-table-has-column):

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

Моя функция обновления имеет следующие проверки (обратите внимание, что у меня установлен пакетный флаг, который добавляет строку with op.batch_alter_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))
person Charles L.    schedule 18.10.2018