前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flask 中的数据库迁移

Flask 中的数据库迁移

作者头像
Python碎片公众号
发布2021-02-26 15:42:43
1.7K0
发布2021-02-26 15:42:43
举报
文章被收录于专栏:Python碎片公众号的专栏

在我之前使用 Flask 实现简单接口时,为了方便,我每次都会将数据表删除掉,然后重新创建表和添加数据。因为测试数据只有几条,所以可以使用删表重建的方式,但在实际的项目中,是不可能使用这种方式的,删表意味着删数据。

在开发过程中,有时候需要修改数据库模型,比如新功能需要增加一个字段,在 Flask 代码中修改模型类后,要将新增的字段同步到数据库中。这时候是不能删表重建的。

在 Flask 中,可以使用数据库迁移来解决这个问题,数据库迁移可以追踪数据模型类的变化,然后把变动应用到数据库中,不会删表造成数据丢失。

一、安装 Flask-Migrate 和 Flask-Script

在 Flask 中使用 Flask-Migrate 扩展,来实现数据迁移。

Flask-Migrate 的文档路径:https://flask-migrate.readthedocs.io/en/latest/ ,内容不多,可以看看。

先安装 Flask-Migrate 。

代码语言:javascript
复制
pip install Flask-Migrate

执行安装命令,会自动下载和安装 Flask-Migrate 模块及相关的依赖库。

其中一个非常重要的依赖库是 Alembic ,数据库迁移时自动生成迁移文件和迁移脚本都是 Alembic 完成的,也是因为 Alembic 的机制,数据库迁移操作只能在 Linux 系统中使用,不能在 Windows 中使用。

具体可以仔细研究一下 Alembic ,文档路径:https://alembic.sqlalchemy.org/en/latest/tutorial.html 。

另外,需要用到 Flask-Script 模块,使用 Flask-Script 来管理 Flask 应用程序 app ,Flask 程序中的操作可以通过命令来完成。

Flask-Migrate 提供了一个 MigrateCommand 类,将这个类添加到 Flask-Script 的 Manager 对象中,可以更方便地使用命令来进行数据库迁移,Flask-Migrate 文档中也是推荐这种方式的。

所以,也要安装 Flask-Script 。

代码语言:javascript
复制
pip install Flask-Script

二、准备数据库迁移的模型类

在项目文件夹下创建一个 flask_migrate_db.py 文件,注意文件名不要叫 flask_migrate.py ,否则会与 Flask-Migrate 中的文件名冲突,导包时就会报错。

先在 flask_migrate_db.py 中编写如下代码,做好数据库迁移的准备。

代码语言:javascript
复制
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager

app = Flask(__name__)
manager = Manager(app)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://admin:Mysql!123@127.0.0.1:3306/MyDB_two'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_ECHO'] = True
app.config['SECRET_KEY'] = 'NFAIOSDFHASOGHAOSPIGAOWE'
db = SQLAlchemy(app)

migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)


class Computer(db.Model):
    __tablename__ = 'Computer_tb'
    cid = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    # price = db.Column(db.Integer)
    # color = db.Column(db.String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('User_tb.uid'))

    def __repr__(self):
        return 'Computer_name: {}'.format(self.name)


class User(db.Model):
    __tablename__ = 'User_tb'
    uid = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    phones = db.relationship('Computer', backref='user', lazy='dynamic')

    def __repr__(self):
        return 'User_name: {}'.format(self.name)


@app.route('/')
def index():
    return 'Hello Migrate!'


if __name__ == '__main__':
    # user_one = User(name='You')
    # db.session.add(user_one)
    # computer_one = Computer(name='Dell', user_id=1)
    # db.session.add(computer_one)
    # db.session.commit()

    manager.run()

代码中连接了 mysql 数据库 MyDB_two,这个数据库需要提前创建好。将 Flask 应用对象 app 和数据库连接对象 db 传入 Migrate ,创建迁移对象 migrate 。将 MigrateCommand 添加到 Flask-Script 的 Manager 中,最后使用 Manager 管理和运行 app 。

代码中定义了两个数据库模型类 Computer 和 User ,执行数据库迁移后会在 MyDB_two 中创建两张表 Computer_tb 和 User_tb 。

三、执行数据库迁移

1. 初始化迁移仓库

代码语言:javascript
复制
python flask_migrate_db.py db init

在项目目录下执行 init 初始化命令,会自动在项目目录下创建一个 migrations 目录。这个目录是 Alembic 模块自动创建的,默认名字叫 migrations ,可以在创建 migrate = Migrate(app, db) 对象时传入 directory='filename' 参数自定义名字。

migrations 里面有一个 versions 文件夹,这个文件夹用于存放迁移脚本,执行迁移命令后会自动生成迁移脚本保存在里面。

env.py 是迁移环境的相关信息。

数据库迁移时,初始化命令只需要执行一次,如果在一开始发现执行有问题,需要重新初始化,要先删除 migrations 目录才行。如果已经执行迁移命令,需要重新初始化,要先删除 migrations 目录和到数据库中删除 alembic_version 表。

2. 创建迁移脚本

代码语言:javascript
复制
python flask_migrate_db.py db migrate -m "create table"

继续执行 migrate 命令生成迁移脚本,通过 -m 参数添加迁移信息,这类似于 git 提交代码时添加提交信息。

执行命令后,会在 versions 目录下生成一个迁移脚本,迁移脚本的名字是版本 id 和迁移信息拼接的结果,打开迁移脚本,脚本里定义了一个 upgrade() 函数,函数里的代码就是创建数据表的代码,感兴趣可以打开看看。

每次数据模型类有变化,需要迁移数据库时,都需要执行创建迁移脚本的命令,生成新版本的迁移脚本。

3. 执行数据库迁移

代码语言:javascript
复制
python flask_migrate_db.py db upgrade

生成迁移脚本后,数据库还没有变化,迁移结果还没有生效,需要继续执行 upgrade 命令,使迁移结果应用到数据库中。执行 upgrade 命令相当于执行迁移脚本中的 upgrade() 函数,执行里面创建表的代码。

执行 upgrade 命令后,会在数据库中创建一张 alembic_version 表,这张表不是代码中定义的,是 Alembic 自动创建的(看名字就知道了),里面保存的是当前数据库的版本 id ,alembic_version 表不能删除,删除后就不能继续执行数据库迁移操作了,除非重新初始化。

同时,执行 upgrade 命令后,会根据代码中定义的模型类创建对应的表,表的字段与模型类中定义的一致。

如果数据库中有其他表(没有对应模型类的表),会被删除。这点需要特别注意,数据库迁移时最好使用一个新的数据库(不要与其他项目用同一个数据库),避免造成数据丢失。

每次生成迁移脚本后,都需要执行 upgrade 命令,迁移结果才会生效。

4. 添加数据和添加字段

现在已经执行了第一次数据库迁移,数据库中创建了对应的表,但是表都是空的,没有数据。

添加下面的代码,然后 python flask_migrate_db.py 运行代码,在两张表里面各添加一条数据。

代码语言:javascript
复制
    user_one = User(name='You')
    db.session.add(user_one)
    computer_one = Computer(name='Dell', user_id=1)
    db.session.add(computer_one)
    db.session.commit()

添加后,到数据库中查询,确认数据添加成功,数据库已经可以正常使用了。

现在,假设需要修改数据库模型类,如需要在模型类 Computer 中增加一个 price 字段。先注释掉添加数据的代码(有唯一字段不能重复运行和添加),然后在 Computer 类中添加一个字段。

代码语言:javascript
复制
    price = db.Column(db.Integer)

5. 生成新版本数据库迁移脚本

代码语言:javascript
复制
python flask_migrate_db.py db migrate -m "add price to computer"

模型类的代码修改后,数据表并没有变化,需要重新生成迁移脚本和执行数据库迁移。

执行命令后,会生成一个新的迁移脚本,打开新的迁移脚本,脚本里面的代码就是执行数据库新增字段的代码。

前面提到,在 Linux 系统中可以顺利执行数据库迁移,在 Windows 中会失败,是因为 Alembic 生成迁移脚本的机制,现在就简单解释一下原因。

执行上面相同的操作后,打开迁移脚本,Linux 系统和 Windows 系统中生成的迁移脚本代码是不同的。Linux 中的脚本代码是直接添加字段,Windows 中的脚本代码包含了删除关系字段、删除表和重新创建表的代码,而且顺序是乱的(创建在前删除在后,删除表的顺序也不对),所以在 Windows 中执行迁移时会失败。

如果要在 Windows 中成功执行数据库迁移,就不能直接使用 Alembic 生成的迁移脚本,需要自己修改迁移脚本。可以调整迁移脚本中代码的顺序,先删除关系字段,关系表,然后删除其他表,最后创建新表,这样执行迁移后,相当于删表重建,表结构修改成功了,但是数据丢失了。更好的方法是将代码改成增加字段的代码(与Linux中的一样),再执行迁移,就能完成修改表结构并保留数据。

所以,要在 Windows 中执行数据库迁移,要知道怎么改迁移脚本(与模型类变化一致,改时要细心)。

6. 执行迁移

代码语言:javascript
复制
python flask_migrate_db.py db upgrade

最后执行 upgrade 命令使迁移脚本生效。

执行之后,成功在 Computer_tb 表中增加了字段 price 。

再查询一下数据,看数据是否丢失。

可以看到,数据都保留着,之前的数据没有新字段的值,默认为空 NULL 。

7. 其他操作

在所有迁移脚本中,除了 upgrade() 函数外,还有一个 downgrade() 函数,这两个函数里面的代码是相反的,downgrade() 函数是用于回退数据库迁移的。

upgrade() 函数把迁移中的改动应用到数据库中,downgrade() 函数则将改动删除。

代码语言:javascript
复制
python flask_migrate_db.py db downgrade

执行 downgrade 命令如果不指定版本 id ,默认是回退到上一个版本,即版本 -1 (减一),也可以指定版本回退。

对数据库迁移后,可以使用 history 命令找到历史的版本号和变更过程。

代码语言:javascript
复制
python flask_migrate_db.py db history

此外,数据库迁移时还可以指定参数来完成更多的功能,如初始化时指定 --multi 参数可以实现多数据库迁移(同时使用多种数据库,如 mysql + postgresql ),生成迁移脚本和执行迁移时使用 --sql 参数可以查看数据库迁移命令对应的原生 SQL 语句。具体使用方法可以去查看 Flask-Migrate 的文档。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python 碎片 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档