Use Sqlalchemy-migrate

记录一下使用 sqlalchemy-migrate 的问题。

官网: https://sqlalchemy-migrate.readthedocs.io/en/latest/download.html

说明

在寻找 python 层面,类 rails migration 的工具,发现了 sqlalchemy-migrate。 大致看着还可以,尝试使用中。

下载

1
pip install sqlalchemy-migrate

安装成功后,应该可以运行

1
migrate help

可以查看 migrate 脚本支持的功能命令。

使用

根据官网说明,手动尝试运行,但遇到了些问题。

创建迁移项目目录

1
migrate create migration "Example project"

此命令会创建一个迁移项目的文件夹 migration,里面包含有 versions 目录、manage.py、manage.cfg 文件。

构建数据库的基本结构

官网上,有

1
$ python migration/manage.py version_control mysql+mysqldb://root:@localhost/activity?charset=utf8mb4 migration

官网上说,这命令会在相应的数据库中增加版本控制的表 migrate_version。但在我的机器中,会出现错误

1
2
3
4
Traceback (most recent call last):
  File "migration/manage.py", line 2, in <module>
    from migrate.versioning.shell import main
ModuleNotFoundError: No module named 'migrate'

查阅文件 migration/manage.py 文件,

1
2
3
4
5
#!/usr/bin/env python
from migrate.versioning.shell import main

if __name__ == '__main__':
    main(debug='False')

报错没有正常找到 migrate 包,折腾了许久,没有找到有效的解决方案。 但本质上,migration/manage.py 文件也是使用 migrate 命令去实现迁移操作的, 所以,尝试手动使用 migrate 命令去实现数据迁移。

1
migrate version_control mysql+mysqldb://root:@localhost/activity?charset=utf8mb4 migration

运行上面的命令之后,查看数据库,会发现有数据表 migrate_version。

查看当前版本

1
2
migrate db_version mysql+pymysql://root:@localhost/activity?charset=utf8mb4 migration
# 0

创建迁移脚本

创建迁移脚本使用 script 命令实现

1
migrate script "add init tables" migration

命令会生成文件 migration/xxx_add_init_tables.py 文件,xxx 可以是 001 增序编号,也可以是日期时间。

查阅文件,有

1
2
3
4
5
6
7
8
9
10
11
12
13
from sqlalchemy import *
from migrate import *


def upgrade(migrate_engine):
    # Upgrade operations go here. Don't create your own engine; bind
    # migrate_engine to your metadata
    pass


def downgrade(migrate_engine):
    # Operations to reverse the above upgrade go here.
    pass

遇到问题:使用timestamp做为文件名前缀时,migrate包的部分版本处理有错误,建议使用普通数字。

增加一个 users 表, 有代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sqlalchemy import *
from migrate import *

meta = MetaData()
account = Table(
    'account', meta,
    Column('id', Integer, primary_key=True),
    Column('login', String(40)),
    Column('passwd', String(40)),
)

def upgrade(migrate_engine):
    meta.bind = migrate_engine
    account.create()


def downgrade(migrate_engine):
    meta.bind = migrate_engine
    account.drop()

例子中,利用 sqlalchemy 构建表,并分别定义了 upgrade 、downgrade 方法。方法中,分别对 account 表进行了创建或删除。

代码中定义了表,需要将表落实到数据库中,运行命令

1
migrate upgrade mysql+pymysql://root:@localhost/activity?charset=utf8mb4 migration

命令会直接在数据库创建相应的表。

想删除表,可以执行

1
migrate downgrade mysql+pymysql://root:@localhost/activity?charset=utf8mb4 migration 0

0 表示要回滚到的版本。

Comments