2015-05-22 3 views
12

Я использую SqlAlchemy и Flask-migrate для миграции DB. Я успешно init БД и upgrade один раз, но когда я удалил одну из моей колонки таблицы, мне удалось migrate однако upgrade дал мне следующую ошибку:Почему Flask-migrate не может обновиться, когда столбец сбрасывается

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) near "DROP": syntax error [SQL: u'ALTER TABLE posts DROP COLUMN tags'] 

Там есть часть моего models.py

class Post(db.Model): 
    __tabelname__ = 'posts' 
    id = db.Column(db.Integer, primary_key=True) 
    body = db.Column(db.UnicodeText) 
    # tags = db.Column(db.Unicode(32)) 
    # I deleted this field, upgrade give me error 

    .... 

И я запустил python manage.py db upgrade снова, ошибка изменилась!

(venv)[email protected]:~/manualscore$ python manage.py db upgrade 
INFO [alembic.migration] Context impl SQLiteImpl. 
INFO [alembic.migration] Will assume non-transactional DDL. 
INFO [alembic.migration] Running upgrade 555b78ffd5f -> 2e063b1b3164, add tag table 
Traceback (most recent call last): 
    File "manage.py", line 79, in <module> 
    manager.run() 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/flask_script/__init__.py", line 405, in run 
    result = self.handle(sys.argv[0], sys.argv[1:]) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/flask_script/__init__.py", line 384, in handle 
    return handle(app, *positional_args, **kwargs) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/flask_script/commands.py", line 145, in handle 
    return self.run(*args, **kwargs) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/flask_migrate/__init__.py", line 177, in upgrade 
    command.upgrade(config, revision, sql=sql, tag=tag) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/command.py", line 165, in upgrade 
    script.run_env() 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/script.py", line 390, in run_env 
    util.load_python_file(self.dir, 'env.py') 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/util.py", line 243, in load_python_file 
    module = load_module_py(module_id, path) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/compat.py", line 79, in load_module_py 
    mod = imp.load_source(module_id, path, fp) 
    File "migrations/env.py", line 72, in <module> 
    run_migrations_online() 
    File "migrations/env.py", line 65, in run_migrations_online 
    context.run_migrations() 
    File "<string>", line 7, in run_migrations 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/environment.py", line 738, in run_migrations 
    self.get_context().run_migrations(**kw) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/migration.py", line 309, in run_migrations 
    step.migration_fn(**kw) 
    File "/home/ncp/manualscore/migrations/versions/2e063b1b3164_add_tag_table.py", line 24, in upgrade 
    sa.PrimaryKeyConstraint('id') 
    File "<string>", line 7, in create_table 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/operations.py", line 944, in create_table 
    self.impl.create_table(table) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 198, in create_table 
    self._exec(schema.CreateTable(table)) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/alembic/ddl/impl.py", line 122, in _exec 
    return conn.execute(construct, *multiparams, **params) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute 
    return meth(self, multiparams, params) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection 
    return connection._execute_ddl(self, multiparams, params) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 968, in _execute_ddl 
    compiled 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context 
    context) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1339, in _handle_dbapi_exception 
    exc_info 
    File "/home/ncp/manualscore/venv/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/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context 
    context) 
    File "/home/ncp/manualscore/venv/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 442, in do_execute 
    cursor.execute(statement, parameters) 
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) table tags already exists [SQL: u'\nCREATE TABLE tags (\n\tid INTEGER NOT NULL, \n\tname VARCHAR(32), \n\tpost_id INTEGER, \n\tPRIMARY KEY (id), \n\tFOREIGN KEY(post_id) REFERENCES posts (id)\n)\n\n'] 
+0

не хватает информации. – plaes

+0

В отличие от сайтов форума, мы не используем «Спасибо», или «Любая помощь оценена», или подписи на [so]. См. «[Должны ли« Привет »,« спасибо », теги и приветствия удалены из сообщений?] (Http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be - спасибо за сообщение). Кстати, это «Спасибо заранее», а не «Спасибо в продвинутом». –

ответ

17

SQLite не поддерживает сброс или изменение столбцов. Тем не менее, есть способ обойти это, внося изменения на уровне таблицы: https://www.sqlite.org/lang_altertable.html

И более полезно для пользователей Alembic/Flask-Migrate, контекстный менеджер Alembic's batch_alter_table позволяет вам естественным образом определять изменения и делать немного «сделать новую таблицу - скопировать данные - отбросить старую таблицу - переименовать новую таблицу» танцевать за кулисами при использовании SQLite. См: http://alembic.zzzcomputing.com/en/latest/batch.html

Таким образом, функция обновления() в файле миграции должен содержать что-то вроде:

with op.batch_alter_table('posts') as batch_op: 
    batch_op.drop_column('tags') 

Я боюсь, что я не знаю, почему ошибка изменилась во второй раз вы пытались обновления.

Как указывает tkisme, вы также можете настроить флаг EnvironmentContext.configure.render_as_batch в env.py, чтобы сценарии автоматической генерации миграции использовали batch_alter_table по умолчанию. См: http://alembic.zzzcomputing.com/en/latest/batch.html#batch-mode-with-autogenerate

+6

Я подчиняюсь этой проблеме, связанной с sqlite. Но почему это не обнаруживает alembic это само по себе и использует предлагаемый batch_op? – buhtz

+1

Для alembic текущая ссылка: http://alembic.zzzcomputing.com/ru/latest/batch.html –

5

изменение Перемещения/env.py добавить render_as_batch=True в context.configure

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. 

    """ 

    # this callback is used to prevent an auto-migration from being generated 
    # when there are no changes to the schema 
    # reference: http://alembic.readthedocs.org/en/latest/cookbook.html 
    def process_revision_directives(context, revision, directives): 
     if getattr(config.cmd_opts, 'autogenerate', False): 
      script = directives[0] 
      if script.upgrade_ops.is_empty(): 
       directives[:] = [] 
       logger.info('No changes in schema detected.') 

    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, 
         process_revision_directives=process_revision_directives, 
         render_as_batch=True,# this is new feature 
         **current_app.extensions['migrate'].configure_args) 

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

 Смежные вопросы

  • Нет связанных вопросов^_^