Alembic: изменить тип столбца с помощью USING

Я пытаюсь использовать перегонный куб для преобразования поля SQLAlchemy PostgreSQL ARRAY(Text) в поле BIT(variing=True) для одного из столбцов моей таблицы.

В настоящее время столбец определяется как:

cols = Column(ARRAY(TEXT), nullable=False, index=True)

Я хочу изменить его на:

cols = Column(BIT(varying=True), nullable=False, index=True)

Изменение типов столбцов, по-видимому, не поддерживается по умолчанию, поэтому я редактирую сценарий перегонного куба вручную. Это то, что у меня есть на данный момент:

def upgrade():
    op.alter_column(
        table_name='views',
        column_name='cols',
        nullable=False,
        type_=postgresql.BIT(varying=True)
    )


def downgrade():
    op.alter_column(
        table_name='views',
        column_name='cols',
        nullable=False,
        type_=postgresql.ARRAY(sa.Text())
    )

Однако запуск этого скрипта дает ошибку:

Traceback (most recent call last):
  File "/home/home/.virtualenvs/deus_lex/bin/alembic", line 9, in <module>
    load_entry_point('alembic==0.7.4', 'console_scripts', 'alembic')()
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/config.py", line 399, in main
    CommandLine(prog=prog).main(argv=argv)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/config.py", line 393, in main
    self.run_cmd(cfg, options)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/config.py", line 376, in run_cmd
    **dict((k, getattr(options, k)) for k in kwarg)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/command.py", line 165, in upgrade
    script.run_env()
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/script.py", line 382, in run_env
    util.load_python_file(self.dir, 'env.py')
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/util.py", line 242, in load_python_file
    module = load_module_py(module_id, path)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/compat.py", line 79, in load_module_py
    mod = imp.load_source(module_id, path, fp)
  File "./scripts/env.py", line 83, in <module>
    run_migrations_online()
  File "./scripts/env.py", line 76, in run_migrations_online
    context.run_migrations()
  File "<string>", line 7, in run_migrations
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/environment.py", line 742, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/migration.py", line 305, in run_migrations
    step.migration_fn(**kw)
  File "/home/home/deus_lex/winslow/scripts/versions/2644864bf479_store_caselist_column_views_as_bits.py", line 24, in upgrade
    type_=postgresql.BIT(varying=True)
  File "<string>", line 7, in alter_column
  File "<string>", line 1, in <lambda>
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/util.py", line 387, in go
    return fn(*arg, **kw)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/operations.py", line 470, in alter_column
    existing_autoincrement=existing_autoincrement
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 147, in alter_column
    existing_nullable=existing_nullable,
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 105, in _exec
    return conn.execute(construct, *multiparams, **params)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 729, in execute
    return meth(self, multiparams, params)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 69, in _execute_on_connection
    return connection._execute_ddl(self, multiparams, params)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 783, in _execute_ddl
    compiled
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 958, in _execute_context
    context)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1159, in _handle_dbapi_exception
    exc_info
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 951, in _execute_context
    context)
  File "/home/home/.virtualenvs/deus_lex/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 436, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (ProgrammingError) column "cols" cannot be cast automatically to type bit varying
HINT:  Specify a USING expression to perform the conversion.
 'ALTER TABLE views ALTER COLUMN cols TYPE BIT VARYING' {}

Как я могу изменить свой сценарий с помощью выражения USING?


person bard    schedule 16.03.2015    source источник


Ответы (2)


К сожалению, вам нужно использовать необработанный SQL, поскольку перегонный куб никогда не выводит оператор USING при изменении типов.

Однако написать собственный SQL для этого довольно просто:

op.execute('ALTER TABLE views ALTER COLUMN cols TYPE bit varying USING expr')

Конечно, вы должны заменить expr выражением, которое преобразует старый тип данных в новый тип данных.

person ThiefMaster    schedule 06.05.2015

Начиная с версии 0.8.8, alembic поддерживает USING PostgreSQL с параметром postgresql_using:

op.alter_column('views', 'cols', type_=postgresql.BIT(varying=True), postgresql_using='col_name::expr')
person Dag Høidahl    schedule 15.11.2016
comment
+1 за сохранение миграции в коде, чтобы вы могли легко воспроизвести состояние базы данных в других средах. Чтобы узнать больше о выражении USING, цель состоит в том, чтобы сообщить postgres, как преобразовать все текущие сохраненные значения в новый тип. Например, изменяя целочисленный столбец на varchar, вы должны использовать что-то вроде col_name::varchar(32). - person Hartley Brody; 22.12.2016
comment
Это было именно то, что я искал прямо сейчас. :) - person Martin Thorsen Ranang; 14.03.2017
comment
Это должен быть принятый ответ. Действительно непросто найти документацию о postgresql_using... - person Neau Adrien; 05.05.2021