iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
Software Development

FastAPI 開發筆記:從新手到專家的成長之路系列 第 17

[Day 17] 資料庫 (四):用 Alembic 做資料庫初始化與 Migration

  • 分享至 

  • xImage
  •  

有時候,我們需要在資料庫內先存放一些基本資料,才比較方便我們後續使用 (或進行測試),這個過程我們就稱為「初始化 (Initialization)」。

建立空資料庫其實也應該算做初始化的一部分

資料庫初始化

要在資料庫先存放資料本身並不難,其實簡單一點的作法就是使用昨天提到的 CRUD。只要在啟動 FastAPI 時檢查資料庫內是否有資料 (或是是否含有某一筆預設資料),如果沒有,就執行事先寫好的操作資料庫的腳本,讓 SQLAlchemy 幫我們新增資料到資料庫中,就能做到初始化的效果。

這樣的做法在小專案或沒那麼複雜的專案裡是沒有問題的,但如果初始化的狀態比較複雜,後續在版本控制或是誤刪初始資料時,有可能導致再度初始化。因此,保險一點的作法是引入版本控制的概念,將空資料庫視作第一版,而資料庫初始化後的結果視作第二個版本,並將這個初始化流程視作版本更新 (更貼切一點的說法是 migration)。

我一直找不到 Migration 的理想中文翻譯,我覺得翻作「遷移」有點怪

想要做資料庫的版本控制,FastAPI 官網的建議是使用 Alembic

FastAPI 也是建議使用 Alembic 來進行資料庫初始化 (連結)

Alembic 是什麼?

Alembic 是 SQLAlchemy 作者開發做為資料庫 Migration 的工具,本身與 FastAPI 是獨立的 (換句話說,就算沒有安裝 FastAPI 也可以用 Alembic 幫 SQLAlchemy 做 migration)。(Github) (文件)

大家可以去看看這篇文章,它對如何用 Alembic 做 migration 有很詳細的教學

Alembic

安裝

首先,要先安裝 Alembic

pip install alembic

Alembic 初始化

接下來,我們需要進行設定,因此用下面這行指令來產生設定檔

alembic init testAlembic

其中,init 後面的參數是資料夾名稱,可以自行決定。

輸入完之後就會發現新增了一個 testAlembic 資料夾 (裡面的 versions 資料夾是空的),以及 alembic.ini

接著打開 alembic.ini,找到 sqlalchemy.url,將它改成我們在 database.py 內所設定的資料庫連線 URL,也就是 sqlite:///./test.db
(預設是 driver://user:pass@localhost/dbname )

忘記資料庫連線 URL 的人可以去看 [Day 14] 的介紹

建立 migration script

設定完成後就可以開始建立 migration script 了。

Alembic 有提供手動和自動建立的方法,我們介紹手動的部份就好,自動的部份可以看上面的教學文章或是官方文件

我覺得沒有很複雜的話,用手動建立就好,速度不會差太多。但如果真的很複雜,我也會怕自動建立的過程出錯,還是要反覆檢查,因此我自己都是用手動建立的 XD

手動建立的指令如下

alembic revision -m "create user table"

其中 -m 後面的參數就是放這次更新的說明 (別寫太長,它會成為檔名 XD)

可以看到 versions 資料夾內多了一個檔案 b6f25e44ac91_create_user_table.py

Alembic 在每個版本都會自動建立一個 ID 做為版本號 (這次是 b6f25e44ac91)

這是裡面預設的內容

"""create user table

Revision ID: b6f25e44ac91
Revises: 
Create Date: 2023-09-30 22:54:28.736201

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = 'b6f25e44ac91'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    pass


def downgrade() -> None:
    pass

接下來就要來手動調整 upgrade()downgrade() 內的內容了。

這邊我們用 Alembic 官網範例

def upgrade():
    op.create_table(
        'testuser',
        sa.Column('id', sa.Integer, primary_key=True),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('description', sa.Unicode(200)),
    )

def downgrade():
    op.drop_table('testuser')

不小心再用了一個 user,所以表格名稱改成 testuser XD

執行 migration script

接著在 terminal 輸入 alembic upgrade head

成功之後,打開 test.db,就會發現多了兩個表格,一個是剛剛在腳本裡寫的 testuser,另一個是 Alembic 用來記錄當前版本用的 alembic_version

查看當前版本

此時,可以再回到 terminal 輸入 alembic current 來查看當前本

其他常用指令

alembic downgrade -1
降一個版本,也可以用 -2 降兩個版本 (以此類推),如果不想數要講幾個版本的話,也可以直接輸入版本號

alembic history
查看各版本的資訊,加上 --verbose 則可以看到詳細資訊

重點回顧

今天主要是介紹 Alembic 的使用,包含了

  1. 安裝設定
  2. 手動建立 migration script
  3. 執行 migration

資料庫的部份就先告一個段落了,原本還想介紹動態生成表格的做法 (無法事先知道完整的表格格式),但找不到好地方放進去,因此只好先捨棄掉。

關鍵字:MetaData

明天會開始討論錯誤處理~


上一篇
[Day 16] 資料庫 (三):增刪查改 CRUD
下一篇
[Day 18] 錯誤處理 (一):HTTPException
系列文
FastAPI 開發筆記:從新手到專家的成長之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言