Photo by Nathan Dumlao / Unsplash

Background

因為有多個專案要用到同一個資料庫的需求. 但開發人員又彼此沒有很同步. 所以才有把資料庫獨立出來的需求. 那獨立出來還是希望他有migration的功能. 才有了這篇文章. 以下的DB以postgres為例.

Installation

$ pip3 install alembic
$ alembic init alembic

完成後會產生下列檔案:

  • alembic.ini: 設定資料庫連線的相關設定, e.g. sqlalchemy.url = postgresql://user:password@host/dbname

設定好alembic.ini我們便可以繼續下去.

Start

開始建立我們第一個revision.

$ alembic revision -m "create user table"
  Generating /Users/taiker/workspace/alembic/alembic/versions/41cf3ebffbf4_create_user_table.py ... done
  • 41cf3ebffbf4 為revision id.
$ alembic edit head

介紹一下這個指令, 通常我很懶, 懶到不想去複製revision id. 所以我都會利用 alembic edit 來幫助我編輯revusion檔. (head表示為最新的revision id的意思, 你也可以把head換成你想要的
revision id).

接著我們來看一下裡面檔案長什麼樣子.

/alembic/versions/41cf3ebffbf4_create_user_table.py

"""create user table

Revision ID: 41cf3ebffbf4
Revises:
Create Date: 2018-03-11 14:40:36.370365

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '41cf3ebffbf4'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    pass


def downgrade():
    pass

其實跟 Flask-Migrate 出來的檔案長蠻像的. 但還是稍微解釋一下, revision & down_revision. 這是你目前的revision_id & 你之後如果想要 revert 回去你需要對訂哪一個revision_id. (那目前down_revision=None是因為他是第一個revision檔)

upgrade() & downgrade() 分別就是你希望升級後DB長什麼樣子的script & 如果你之後DB要復原你需要透過什麼樣的script來還原DB目前的樣子.

舉個例子:

def upgrade():
    op.create_table(
        'user',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('gender', sa.Integer, nullable=False),
    )

def downgrade():
    op.drop_table('user')
  • upgrade(): 我需要創造一個Table叫user. 裡面包含我所需要的columns.
  • downgrade(): 我要復原到現在DB的架構. 那就把這個user的table給drop掉即可.

完成script之後我們需要透過指令來讓我們寫好的script對DB進行動作

$ alembic upgrade head
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 41cf3ebffbf4, create user table

透過上述的指令可以看到最新的revision檔裡面的upgrade fun已經被執行. 這時候你可以去check你的DB有沒有完成這個動作. 可以看到多了一個user table

basic=# \dt public.*
             List of relations
 Schema |      Name       | Type  | Owner
--------+-----------------+-------+--------
 public | alembic_version | table | taiker
 public | user            | table | taiker
basic=# \d user
                                   Table "public.user"
 Column |         Type          | Collation | Nullable |             Default
--------+-----------------------+-----------+----------+----------------------------------
 id     | integer               |           | not null | nextval('user_id_seq'::regclass)
 name   | character varying(50) |           | not null |
 gender | integer               |           | not null |
Indexes:
    "user_pkey" PRIMARY KEY, btree (id)

那接著我們來測試 downgrade 指令

$ alembic downgrade -1
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running downgrade 41cf3ebffbf4 -> , create user table

透過上述的指令可以看到最新的revision檔裡面的downgrade fun已經被執行. 一樣check一下DB

basic=# \dt public.*
             List of relations
 Schema |      Name       | Type  | Owner
--------+-----------------+-------+--------
 public | alembic_version | table | taiker
(1 row)

這樣你就可以運行 Alembic 的基本功能了, enjoy it.

Reference