Flask-Migrate

情境

會選擇 Flask-Migrate 純粹是因為我目前是使用 Flask 框架,Flask-Migrate 底層使用 Alembic,Alembic 的作者就是 Mike Bayer,如果用過 SQLAlchemy 應該對他不陌生。

基本上 Alembic 還不能偵測所有改變,像是表格更名、欄位更名、匿名限制等。

但是因為我的需求很簡單,只要能夠讓我的 schema 變更入版控,以及指令調整 schema 即可。

安裝

1
(venv) $ pip install Flask-Migrate

使用方式

初始環境

首次使用需要先執行以下指令,來產生 migrations/ 目錄,之後這個目錄要進版控。

1
2
3
4
$ flask db init

#### 等同 alembic 的指令
# $ alembic init migrations

以我的專案目錄結構為例,會在 mypkg/ 下執行指令產生 migrations/。

1
2
3
4
5
6
myproj/
mypkg/
static/
templates/
migrations/
....

編輯 model

使用 SQLAlchemy ,產生一個 Model,像是:

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding: utf-8 -*-

class User(object):

email = db.Column(db.String(190), unique=True, nullable=False)
name = db.Column(db.String(50), unique=False, nullable=True)

產生 migration scripts

1
2
3
$ flask db migrate

# $ alembic revision --autogenerate -m "create user"

接著只要執行上述指令,就會偵測現有的 model,來動態產生 migration 指令檔,產生出來的指令放在 migrations/versions/ 下。

正如先前所說的,目前還不能偵測得很全面,所以建議打開指令檔檢視與修改。但是如果你的需求跟我一樣單純,那就可以免了。

隨著開發時間拉長,scripts 可能累積很多,那可以考慮全部刪除,然後直接重新執行這個指令,就會把現狀的 schema 濃縮產生到新檔案中。

執行 migration scripts

1
2
3
$ flask db upgrade

# $ alembic upgrade head

執行了這個指令,才真的是把 scripts 生效到資料庫裡。會自行偵測要改變的項目,目前有:

  • table create/delete
  • column create/delete
  • column nullable state
  • basic changes in Indexes and explicitly-named unique constrants
  • basic changes in foreign key constraints

如果只是想要單純生成 sql 語句,而不是生效到資料庫,通常是要遞交 sql 給 DBA 執行,可以:

1
$ flask db upgrade --sql

help

還可以 downgrade,細部指令可以利用 --help 查詢。

1
2
$ flask db --help
$ flask db [command] --help

sqlite 惹的麻煩

跟 sqlite 搭配有個小問題,因為 sqlite 不支援 alter 語法,所以當 column 改名的時候,預設情況下執行 upgrade 會報錯。解決方式在這裡有提到,就是編輯 migrations/env.py 黨,加上 render_as_batch=True 這一行即可。

1
2
3
4
5
context.configure(connection=connection,
target_metadata=target_metadata,
render_as_batch=True,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args)