在使用Flask-Migrate升级/降级数据库时遇到问题。 User
和Post
这两个表由以下类定义:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
我已经在这些表中添加了一些条目。
现在是问题所在。 :)
出于娱乐目的,我通过User
在dummy = db.Column(db.String(20))
表中添加了一个列。修改表架构后,我运行了以下命令:
flask db migrate
----成功flask db upgrade
----成功然后我想返回:
flask db downgrade
----失败,并显示错误:sqlite3.OperationalError: near "DROP": syntax error
dummy = db.Column(db.String(20))
类中删除User
语句来修复错误,然后再次运行flask db downgrade
-再次失败,并出现相同的错误。flask db migrate
----成功flask db upgrade
----再次失败,出现相同的错误。那么长颈瓶迁移的工作原理是什么?具体来说,如何将数据库还原到初始状态(没有dummy
属性)?
谢谢!
答案 0 :(得分:1)
Flask迁移在运行flask db migrate
命令时会生成迁移脚本。您可以查看这些迁移文件中的命令,以查看它们在做什么,并确保它们在做正确的事情。实际上,建议您在运行自动生成的迁移脚本之前先对其进行检查。
如果您更改了某些内容并且不重新运行migrate
命令,那么升级和降级都不会做任何不同的事情,因为它们只是在migration文件夹中运行相应的迁移脚本。
如果数据库不重要,那么最简单的方法是删除数据库和迁移脚本,然后再次运行flask db init
并重新获得有关迁移脚本的新知识,看看能否获得帮助升级和降级。
答案 1 :(得分:1)
从本质上讲,SQLite不支持删除或更改列(显然我猜您使用的是SQLite)。这意味着SQLite不支持ALTER语句,但是关系模式迁移依赖于此语句。
要解决此问题,您必须制作一系列与新结构相对应的SQLite表副本,将数据从现有表转移到新表中,然后删除旧表。
幸运的是,对于Alembic / Flask迁移,有一个上下文管理器(batch_alter_table
),您可以轻松管理所有这些更改。
对于您而言,解决方案是打开迁移脚本,并在downgrade()
方法级别,用以下命令替换那里的指令(可能是op.drop_column('roles', 'dummy')
):
with op.batch_alter_table('roles') as batch_op:
batch_op.drop_column('dummy')
有关更多信息,请参见this link。
一些小细节:
在使用迁移工具时,请切记自动迁移并不总是准确的,并且会遗漏一些细节。自动生成的迁移脚本应始终进行审查。
以防万一,在降级数据库时,请确保删除迁移脚本,然后生成一个新脚本来替换它。