有時候,我們需要在資料庫內先存放一些基本資料,才比較方便我們後續使用 (或進行測試),這個過程我們就稱為「初始化 (Initialization)」。
建立空資料庫其實也應該算做初始化的一部分
要在資料庫先存放資料本身並不難,其實簡單一點的作法就是使用昨天提到的 CRUD。只要在啟動 FastAPI 時檢查資料庫內是否有資料 (或是是否含有某一筆預設資料),如果沒有,就執行事先寫好的操作資料庫的腳本,讓 SQLAlchemy 幫我們新增資料到資料庫中,就能做到初始化的效果。
這樣的做法在小專案或沒那麼複雜的專案裡是沒有問題的,但如果初始化的狀態比較複雜,後續在版本控制或是誤刪初始資料時,有可能導致再度初始化。因此,保險一點的作法是引入版本控制的概念,將空資料庫視作第一版,而資料庫初始化後的結果視作第二個版本,並將這個初始化流程視作版本更新 (更貼切一點的說法是 migration)。
我一直找不到 Migration 的理想中文翻譯,我覺得翻作「遷移」有點怪
想要做資料庫的版本控制,FastAPI 官網的建議是使用 Alembic。
FastAPI 也是建議使用 Alembic 來進行資料庫初始化 (連結)
Alembic 是 SQLAlchemy 作者開發做為資料庫 Migration 的工具,本身與 FastAPI 是獨立的 (換句話說,就算沒有安裝 FastAPI 也可以用 Alembic 幫 SQLAlchemy 做 migration)。(Github) (文件)
大家可以去看看這篇文章,它對如何用 Alembic 做 migration 有很詳細的教學
首先,要先安裝 Alembic
pip install 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 了。
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
接著在 terminal 輸入 alembic upgrade head
成功之後,打開 test.db
,就會發現多了兩個表格,一個是剛剛在腳本裡寫的 testuser
,另一個是 Alembic 用來記錄當前版本用的 alembic_version
此時,可以再回到 terminal 輸入 alembic current
來查看當前本
alembic downgrade -1
降一個版本,也可以用 -2
降兩個版本 (以此類推),如果不想數要講幾個版本的話,也可以直接輸入版本號
alembic history
查看各版本的資訊,加上 --verbose
則可以看到詳細資訊
今天主要是介紹 Alembic 的使用,包含了
資料庫的部份就先告一個段落了,原本還想介紹動態生成表格的做法 (無法事先知道完整的表格格式),但找不到好地方放進去,因此只好先捨棄掉。
關鍵字:
MetaData
明天會開始討論錯誤處理~