我正在使用指南here创建一个测试博客.它非常全面.但是,我在进行Alembic迁移时遇到了麻烦.我可以删除所有版本,并使用所有列来建立一个新数据库.但是,当我添加新列时,我遇到了问题.这是我的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()
这都是很标准的.但是,如果要向“人”表中添加一个随机列,如下所示:
class Person(db.Model):
....
random_column = db.Column(db.Integer())
然后运行python manage.py db迁移(效果很好),然后运行python manage.py db升级,然后出现以下错误:
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表中添加了一个列.我不了解阿勒比奇吗?
就像我说的那样,当我启动一个全新的数据库并加载配置时,它可以完美地找到.只有当我进行更改并尝试迁移时,Alembic才会引发这些错误.有谁知道为什么会这样吗?
编辑
以防万一人们需要查看我的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上关注了the link to the doc,以了解其如何使用Alembic,并说:
The migrate command adds a new migration script. You should review it
and edit it to be accurate, as Alembic cannot detect all changes that
you make to your models. In particular it does not detect indexes, so
those need to be added manually to the script.
Flask-Migrate使用称为“自动生成”的alembic功能,在该功能中尝试将数据库状态与模型进行比较并自动创建差异.
我们直接使用Alembic,我发现autogenerate确实很方便,但是我必须手动编辑它,特别是当您处理索引和约束时.
因此,我的解决方案是按照说的做,并手动编辑迁移文件,并删除不需要的或虚假的行.