Вопрос

Я создаю тестовый блог, используя найденное руководство здесь.Это довольно всеобъемлющая информация.Однако у меня возникли проблемы с миграцией перегонного куба.Я могу стереть все версии и создать новую базу данных со всеми столбцами просто отлично.Но когда я добавляю новый столбец, у меня возникают проблемы.Вот код в моем models.py:

models.py

....
class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    pwdhash = db.Column(db.String(100))
    name = db.Column(db.String(100), unique=True)

    def __init__(self, email, name, password):
        self.email = email
        self.name = name.title()
        self.set_password(password)

    def __repr__(self):
        return '<User %r>' % (self.name)

    def set_password(self, password):
        self.pwdhash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.pwdhash, password)

    @classmethod
    def all(cls):
        return Person.query.all()

class Category(db.Model):
    __tablename__ = 'category'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True)
    description = db.Column(db.Text)

    def __unicode__(self):
        return self.name

class Article(db.Model):
    __tablename__ = 'articles'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    body = db.Column(db.Text)
    created = db.Column(db.DateTime, default=datetime.datetime.now)
    category_name = db.Column(db.String(10), db.ForeignKey(Category.name))
    category = db.relationship(Category)
    person_name = db.Column(db.String(100), db.ForeignKey(Person.name, onupdate="CASCADE", ondelete="CASCADE"))
    person = db.relationship(Person)

    @property
    def slug(self):
        return urlify(self.title)

    @classmethod
    def all(cls):
        return Article.query.order_by(desc(Article.created)).all()

    @classmethod
    def find_by_category(cls, category):
        return Article.query.filter(Article.category_name == category).all()

Все это довольно стандартно.Однако, если бы я добавил случайный столбец в свою таблицу People, например, так:

class Person(db.Model):
    ....
    random_column = db.Column(db.Integer())

затем запустите python manage.py db migrate (который работает нормально) затем запустите python manage.py db upgrade затем я получаю следующую ошибку:

Traceback (most recent call last):
  File "manage.py", line 7, in <module>
    manager.run()
  File "/Library/Python/2.7/site-packages/flask_script/__init__.py", line 397, in run
    result = self.handle(sys.argv[0], sys.argv[1:])
  File "/Library/Python/2.7/site-packages/flask_script/__init__.py", line 376, in handle
    return handle(app, *positional_args, **kwargs)
  File "/Library/Python/2.7/site-packages/flask_script/commands.py", line 145, in handle
    return self.run(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/flask_migrate/__init__.py", line 82, in upgrade
    command.upgrade(config, revision, sql = sql, tag = tag)
  File "/Library/Python/2.7/site-packages/alembic/command.py", line 124, in upgrade
    script.run_env()
  File "/Library/Python/2.7/site-packages/alembic/script.py", line 199, in run_env
    util.load_python_file(self.dir, 'env.py')
  File "/Library/Python/2.7/site-packages/alembic/util.py", line 198, in load_python_file
    module = load_module(module_id, path)
  File "/Library/Python/2.7/site-packages/alembic/compat.py", line 55, in load_module
    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 "/Library/Python/2.7/site-packages/alembic/environment.py", line 652, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/Library/Python/2.7/site-packages/alembic/migration.py", line 225, in run_migrations
    change(**kw)
  File "migrations/versions/4171a9f6ed2a_.py", line 19, in upgrade
    op.drop_index('category_name_key', 'category')
  File "<string>", line 7, in drop_index
  File "<string>", line 1, in <lambda>
  File "/Library/Python/2.7/site-packages/alembic/util.py", line 293, in go
    return fn(*arg, **kw)
  File "/Library/Python/2.7/site-packages/alembic/operations.py", line 716, in drop_index
    self._index(name, table_name, ['x'], schema=schema)
  File "/Library/Python/2.7/site-packages/alembic/ddl/impl.py", line 164, in drop_index
    self._exec(schema.DropIndex(index))
  File "/Library/Python/2.7/site-packages/alembic/ddl/impl.py", line 76, in _exec
    conn.execute(construct, *multiparams, **params)
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 662, in execute
    params)
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 720, in _execute_ddl
    compiled
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 874, in _execute_context
    context)
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 1024, in _handle_dbapi_exception
    exc_info
  File "/Library/Python/2.7/site-packages/sqlalchemy/util/compat.py", line 196, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/base.py", line 867, in _execute_context
    context)
  File "/Library/Python/2.7/site-packages/sqlalchemy/engine/default.py", line 324, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InternalError: (InternalError) cannot drop index category_name_key because constraint category_name_key on table category requires it
HINT:  You can drop constraint category_name_key on table category instead.
 '\nDROP INDEX category_name_key' {}

В нем даже не упоминается название столбца, который я создал в stacktrace, так что это наводит меня на мысль, что с другими таблицами что-то не так.В нем упоминается удаление индекса, но я не делаю ничего подобного при миграции, просто добавляю столбец в People стол.Есть ли что-то в перегонном кубе, чего я не понимаю?

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

РЕДАКТИРОВАТЬ

Просто на случай, если людям захочется увидеть мой config.py файл:

config.py

import os
basedir = os.path.abspath(os.path.dirname(__file__))

#-----Config the app
SECRET_KEY = 'my_key'
CSRF_ENABLED = True

#-----Config Database
SQLALCHEMY_DATABASE_URI = 'postgresql://username:changeme@localhost/test'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')

#-----Config Upload folder
UPLOAD_FOLDER = os.path.realpath('./snb/static') + '/uploads'
Это было полезно?

Решение

Я последовал за ним ссылка на документ на Flask-Migrate, чтобы посмотреть, как он использует перегонный куб, и там написано:

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

Flask-Migrate использует функцию перегонного куба под названием "автогенерация", где она пытается сравнить состояние вашей базы данных с вашими моделями и автоматически создать разницу.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top