Python Web API 實戰 (二):SQLModel 資料庫整合 (第 39 章)

站主自己的課程,請大家支持
揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站? 揭秘站長的架站心法:如何利用 Hugo × AI 打造高質感個人品牌網站?
  • Post by
  • Jan 22, 2024
post-thumb

在 FastAPI 專案中,我們通常使用 ORM (Object Relational Mapping) 來操作資料庫,這樣我們就可以用 Python 物件的方式來寫 SQL,而不需要寫原本的 SQL 語句。

Python 界最強大的 ORM 是 SQLAlchemy,但它有點複雜。於是 FastAPI 的作者開發了 SQLModel,它是 SQLAlchemy + Pydantic 的合體,專為現代 Python 打造。

1. 安裝

pip install sqlmodel

2. 定義模型

SQLModel 的特點是:同一個類別,既是 Pydantic Model (用於驗證),也是 SQLAlchemy Model (用於資料庫)

from typing import Optional
from sqlmodel import Field, SQLModel, create_engine, Session

# 繼承 SQLModel, table=True 代表這是一個資料庫表格
class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    secret_name: str
    age: Optional[int] = None

# 建立 SQLite 資料庫連線
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"

engine = create_engine(sqlite_url, echo=True) # echo=True 會印出 SQL 語句方便除錯

def create_db_and_tables():
    SQLModel.metadata.create_all(engine)

3. 寫入資料 (Create)

def create_heroes():
    hero_1 = Hero(name="Deadpool", secret_name="Wade Wilson")
    hero_2 = Hero(name="Spider-Man", secret_name="Peter Parker")

    # 使用 Session 管理交易 (Transaction)
    with Session(engine) as session:
        session.add(hero_1)
        session.add(hero_2)
        session.commit() # 提交變更

4. 讀取資料 (Read)

from sqlmodel import select

def select_heroes():
    with Session(engine) as session:
        # 寫起來就像 Python 語句
        statement = select(Hero).where(Hero.name == "Deadpool")
        results = session.exec(statement)
        hero = results.first()
        print(hero)

5. 整合 FastAPI

最棒的部分來了:依賴注入 (Dependency Injection)。我們可以讓 FastAPI 自動管理資料庫連線的開啟與關閉。

from fastapi import FastAPI, Depends

app = FastAPI()

# 定義依賴:取得 Session
def get_session():
    with Session(engine) as session:
        yield session

@app.post("/heroes/")
def create_hero(hero: Hero, session: Session = Depends(get_session)):
    session.add(hero)
    session.commit()
    session.refresh(hero) # 獲取資料庫生成的新 ID
    return hero

@app.get("/heroes/")
def read_heroes(session: Session = Depends(get_session)):
    heroes = session.exec(select(Hero)).all()
    return heroes

6. 總結

使用 SQLModel,我們不再需要分開定義 “Pydantic Schema” 和 “Database Model”,一個 Class 搞定全部。

這極大程度地簡化了程式碼,且完美保留了 Type Hints 的優勢。

下一章,也就是 Batch 8 的最後一章,我們將學習如何將寫好的 FastAPI 服務打包成 Docker 容器,準備部署到雲端!


延伸閱讀

LATEST POST
TAG