胖蔡说技术
随便扯扯

Flask使用flask-migrate实现数据库迁移

开发过程中可能会涉及到数据库结构的修改,实现数据库表的更新。一般的我们可以直接操作数据库修改表结构,或者也可以先删除旧表然后新增新表。第一种方式比较简单,操作比较方便,但第二种方式删除旧表可能会导致已有数据丢失的问题。本篇文章主要是介绍如何使用Flask-migrates实现通过代码完成数据的迁移修改。它使用 Alembic 处理 Flask 应用程序的 SQLAlchemy 数据库迁移。数据库操作在 flask db 命令下作为命令行参数提供。

图 1.1 Flask-Migrate 数据迁移

安装插件

我们可以直接通过pip来安装flask-migrate插件:

$pip install flask-migrate

插件使用示例

如同其他flask插件的使用方式一样,我们可以通过flask挂载migrate,并将db、app初始化到migrate上,示例代码如下:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
form flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy()
migrate = Migrate()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128))

def initApp():
    db.init_app(app)
    migrate.init_app(app, db)
    
if __name__ == '__main__':
    initApp()
    app.run()


命令迁移

使用上述应用程序,您可以使用以下命令创建迁移存储库:

$ flask db init

这将向您的应用程序添加一个迁移文件夹。此文件夹的内容需要与其他源文件一起添加到版本控制中。然后您可以生成初始迁移:

$ flask db migrate -m "Initial migration."

迁移脚本需要审查和编辑,因为 Alembic 并不总是能够检测到您对模型所做的每一项更改。特别是,Alembic 目前无法检测表名更改、列名更改或匿名命名的约束。可以在 Alembic 自动生成文档中找到有关限制的详细摘要。完成后,还需要将迁移脚本添加到版本控制中。

然后您可以将迁移脚本描述的更改应用到您的数据库:

$ flask db upgrade

每次数据库模型更改时,重复迁移和升级命令。要在另一个系统中同步数据库,只需从源代码管理刷新迁移文件夹并运行升级命令。要查看所有可用的命令,请运行以下命令:

$ flask db --help

请注意,必须在 FLASK_APP 环境变量中设置应用程序脚本才能使上述所有命令正常工作,正如 flask 命令所要求的那样。如果 db 命令组名称不方便,可以通过传递给 Migrate 类的命令参数更改为不同的名称:

migrate = Migrate(app, db, command='migrate')

Alembic 配置选项

4.0 版开始,Flask-Migrate 自动启用以下在 Alembic 中默认禁用的选项:

  • compare_type=True:此选项配置自动迁移生成子系统以检测列类型更改。
  • render_as_batch=True:此选项使用批处理模式生成迁移脚本,这是一种通过实施“移动和复制”工作流程来解决 SQLite 数据库中许多 ALTER 命令限制的操作模式。使用其他数据库时启用此模式应该没有区别。

要手动配置这些或其他 Alembic 选项,请将它们作为关键字参数传递给 Migrate 构造函数。例子:

migrate = Migrate(app, db, render_as_batch=False)

配置回调

有时应用程序需要将自己的设置动态插入到 Alembic 配置中。一个用配置回调装饰的函数将在配置被读取之后和应用之前被调用。该函数可以修改配置对象,或用不同的对象替换它。

@migrate.configure
def configure_alembic(config):
    # modify config object
    return config

可以简单地通过装饰多个函数来定义多个配置回调。调用多个回调的顺序未确定。

多数据库支持

Flask-Migrate 可以与 Flask-SQLAlchemy 的绑定功能集成,从而可以跟踪到与应用程序关联的多个数据库的迁移。要创建多数据库迁移存储库,请将 --multidb 参数添加到 init 命令:

$ flask db init --multidb

使用此命令,将设置迁移存储库以跟踪主数据库以及 SQLALCHEMY_BINDS 配置选项中定义的任何其他数据库的迁移。

命令参考

Flask-Migrate 公开了一个名为 Migrate 的类。此类包含扩展的所有功能。以下示例使用标准 Flask 命令行界面初始化扩展:

from flask_migrate import Migrate
migrate = Migrate(app, db)

Migrate 的两个参数是应用程序实例和 Flask-SQLAlchemy 数据库实例。 Migrate 构造函数还采用额外的关键字参数,这些参数传递给 Alembic EnvironmentContext.configure() 方法。作为所有 Flask 扩展的标准,Flask-Migrate 也可以使用 init_app 方法进行初始化:

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

db = SQLAlchemy()
migrate = Migrate()

def create_app():
     """Application-factory pattern"""
     ...
     ...
     db.init_app(app)
     migrate.init_app(app, db)
     ...
     ...
     return app

扩展初始化后,一个数据库组将被添加到带有几个子命令的命令行选项中。以下是可用子命令的列表:

  • flask db --help

显示可用命令列表。

  • flask db list-templates

显示可用数据库存储库模板的列表。

  • flask db init [--multidb] [--template TEMPLATE] [--package]

初始化应用程序的迁移支持。可选的 --multidb 启用配置为 Flask-SQLAlchemy 绑定的多个数据库的迁移。 --template 选项允许您明确选择一个数据库存储库模板,可以从此包提供的库存模板中选择,也可以从自定义模板中选择,作为模板目录的路径给出。 --package 选项告诉 Alembic 在迁移和版本目录中添加 __init__.py 文件。

  • flask db revision [--message MESSAGE] [--autogenerate] [--sql] [--head HEAD] [--splice] [--branch-label BRANCH_LABEL] [--version-path VERSION_PATH] [--rev-id REV_ID]

创建一个空的修订脚本。升级和降级更改需要手动编辑脚本。有关如何编写迁移脚本的说明,请参阅 Alembic 的文档。可以包含可选的迁移消息。

  • flask db migrate [--message MESSAGE] [--sql] [--head HEAD] [--splice] [--branch-label BRANCH_LABEL] [--version-path VERSION_PATH] [--rev-id REV_ID]

相当于修订 --autogenerate。迁移脚本填充了自动检测到的更改。应审查和编辑生成的脚本,因为并非所有类型的更改都可以自动检测到。此命令不会对数据库进行任何更改,只会创建修订脚本。

  • flask db edit <revision>

使用 $EDITOR 编辑修订脚本。

  • flask db upgrade [--sql] [--tag TAG] [--x-arg ARG] <revision>

升级数据库。如果未给出修订,则假定为“head”。

  • flask db downgrade [--sql] [--tag TAG] [--x-arg ARG] <revision>

降级数据库。如果未给出修订版,则假定为 -1。

  • flask db stamp [--sql] [--tag TAG] <revision>

将数据库中的修订设置为作为参数给出的修订,而不执行任何迁移。

  • flask db current [--verbose]

显示数据库的当前版本。

  • flask db history [--rev-range REV_RANGE] [--verbose]

显示迁移列表。如果未给出范围,则会显示整个历史记录。

  • flask db show <revision>

显示由给定符号表示的修订。

  • flask db merge [--message MESSAGE] [--branch-label BRANCH_LABEL] [--rev-id REV_ID] <revisions>

将两个修订合并在一起。创建一个新的修订文件。

  • flask db heads [--verbose] [--resolve-dependencies]

在修订脚本目录中显示当前可用的头。

  • flask db branches [--verbose]

显示当前分支点。

注意

  • 所有命令还采用指向包含迁移脚本的目录的 --directory DIRECTORY 选项。如果省略此参数,则使用的目录是迁移。
  • 默认目录也可以指定为 Migrate 构造函数的目录参数。
  • 几个命令中的 --sql 选项执行“离线”模式迁移。需要执行的 SQL 语句将打印到控制台,而不是执行数据库命令。
  • 有关这些命令的详细文档可以在 Alembic 的命令参考页面中找到。

API参考

Flask-Migrate 的命令行界面公开的命令也可以通过从模块 flask_migrate 导入函数以编程方式访问。可用的功能是:

init(directory='migrations', multidb=False)

初始化该应用程序的迁移支持。

revision(directory='migrations', message=None, autogenerate=False, sql=False, head='head', splice=False, branch_label=None, version_path=None, rev_id=None)

创建一个空的修订脚本。

migrate(directory='migrations', message=None, sql=False, head='head', splice=False, branch_label=None, version_path=None, rev_id=None)

创建自动修订脚本。

edit(directory='migrations', revision='head')

使用 $EDITOR 编辑修订脚本。

merge(directory='migrations', revisions='', message=None, branch_label=None, rev_id=None)

将两个修订合并在一起。创建一个新的迁移文件。

upgrade(directory='migrations', revision='head', sql=False, tag=None)

升级数据库。

downgrade(directory='migrations', revision='-1', sql=False, tag=None)

降级数据库。

show(directory='migrations', revision='head')

显示由给定符号表示的修订。

history(directory='migrations', rev_range=None, verbose=False)

显示迁移列表。如果未给出范围,则会显示整个历史记录。

heads(directory='migrations', verbose=False, resolve_dependencies=False)

在脚本目录中显示当前可用的头。

branches(directory='migrations', verbose=False)

显示当前分支点。

current(directory='migrations', verbose=False, head_only=False)

显示数据库的当前版本。

stamp(directory='migrations', revision='head', sql=False, tag=None)

将数据库中的修订设置为作为参数给出的修订,而不执行任何迁移。

  • 这些命令将调用从命令行运行的相同功能,包括输出到终端。 Alembic 将根据 alembic.ini 文件的内容覆盖进程的日志记录配置。
  • 为了获得更大的脚本灵活性,您还可以直接使用 Alembic 公开的 API
赞(2) 打赏
转载请附上原文出处链接:胖蔡叨叨叨 » Flask使用flask-migrate实现数据库迁移
分享到: 更多 (0)

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏