Skip to content

使用 Dataclasses

🌐 AI 與人類共同完成的翻譯

此翻譯由人類指導的 AI 完成。🤝

可能會有對原意的誤解,或讀起來不自然等問題。🤖

你可以透過協助我們更好地引導 AI LLM來改進此翻譯。

英文版

FastAPI 建立在 Pydantic 之上,我之前示範過如何使用 Pydantic 模型來宣告請求與回應。

但 FastAPI 也同樣支援以相同方式使用 dataclasses

from dataclasses import dataclass

from fastapi import FastAPI


@dataclass
class Item:
    name: str
    price: float
    description: str | None = None
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

這之所以可行,要感謝 Pydantic,因為它 內建支援 dataclasses

所以,即使上面的程式碼沒有明確使用 Pydantic,FastAPI 仍會使用 Pydantic 將那些標準的 dataclass 轉換為 Pydantic 版本的 dataclass。

而且當然一樣支援:

  • 資料驗證
  • 資料序列化
  • 資料文件化等

它的運作方式與 Pydantic 模型相同;實際上,底層就是透過 Pydantic 達成的。

Info

請記得,dataclass 無法做到 Pydantic 模型能做的一切。

所以你可能仍然需要使用 Pydantic 模型。

但如果你手邊剛好有一堆 dataclass,這是個不錯的小技巧,可以用來用 FastAPI 驅動一個 Web API。🤓

response_model 中使用 Dataclasses

你也可以在 response_model 參數中使用 dataclasses

from dataclasses import dataclass, field

from fastapi import FastAPI


@dataclass
class Item:
    name: str
    price: float
    tags: list[str] = field(default_factory=list)
    description: str | None = None
    tax: float | None = None


app = FastAPI()


@app.get("/items/next", response_model=Item)
async def read_next_item():
    return {
        "name": "Island In The Moon",
        "price": 12.99,
        "description": "A place to be playin' and havin' fun",
        "tags": ["breater"],
    }

該 dataclass 會自動轉換為 Pydantic 的 dataclass。

如此一來,其結構描述(schema)會顯示在 API 文件介面中:

巢狀資料結構中的 Dataclasses

你也可以將 dataclasses 與其他型別註記結合,建立巢狀的資料結構。

在某些情況下,你可能仍需要使用 Pydantic 版本的 dataclasses。例如,當自動產生的 API 文件出現錯誤時。

這種情況下,你可以把標準的 dataclasses 直接換成 pydantic.dataclasses,它是可直接替換(drop-in replacement)的:

from dataclasses import field  # (1)

from fastapi import FastAPI
from pydantic.dataclasses import dataclass  # (2)


@dataclass
class Item:
    name: str
    description: str | None = None


@dataclass
class Author:
    name: str
    items: list[Item] = field(default_factory=list)  # (3)


app = FastAPI()


@app.post("/authors/{author_id}/items/", response_model=Author)  # (4)
async def create_author_items(author_id: str, items: list[Item]):  # (5)
    return {"name": author_id, "items": items}  # (6)


@app.get("/authors/", response_model=list[Author])  # (7)
def get_authors():  # (8)
    return [  # (9)
        {
            "name": "Breaters",
            "items": [
                {
                    "name": "Island In The Moon",
                    "description": "A place to be playin' and havin' fun",
                },
                {"name": "Holy Buddies"},
            ],
        },
        {
            "name": "System of an Up",
            "items": [
                {
                    "name": "Salt",
                    "description": "The kombucha mushroom people's favorite",
                },
                {"name": "Pad Thai"},
                {
                    "name": "Lonely Night",
                    "description": "The mostests lonliest nightiest of allest",
                },
            ],
        },
    ]
  1. 我們仍然從標準的 dataclasses 匯入 field
  2. pydantic.dataclassesdataclasses 的可直接替換版本。
  3. Author dataclass 內含一個 Item dataclass 的清單。
  4. Author dataclass 被用作 response_model 參數。
  5. 你可以將其他標準型別註記與 dataclass 一起用作請求本文。

在此例中,它是 Item dataclass 的清單。 6. 這裡我們回傳一個字典,其中的 items 是一個 dataclass 清單。

FastAPI 仍能將資料序列化為 JSON。 7. 這裡 response_model 使用的是「Author dataclass 的清單」這種型別註記。

同樣地,你可以把 dataclasses 與標準型別註記組合使用。 8. 注意這個「路徑操作函式」使用的是一般的 def 而非 async def

一如往常,在 FastAPI 中你可以視需要混用 defasync def

如果需要複習何時用哪個,請參考文件中關於 asyncawait 的章節「In a hurry?」。 9. 這個「路徑操作函式」回傳的不是 dataclass(雖然也可以),而是一個包含內部資料的字典清單。

FastAPI 會使用 response_model 參數(其中包含 dataclass)來轉換回應。

你可以把 dataclasses 與其他型別註記以多種方式組合,形成複雜的資料結構。

查看上面程式碼中的註解提示以了解更具體的細節。

延伸閱讀

你也可以將 dataclasses 與其他 Pydantic 模型結合、從它們繼承、把它們包含進你的自訂模型等。

想了解更多,請參考 Pydantic 關於 dataclasses 的文件

版本

自 FastAPI 版本 0.67.0 起可用。🔖