FastAPI教程 請求體 - 嵌套模型

2022-08-20 11:36 更新

使用 FastAPI,你可以定義、校驗(yàn)、記錄文檔并使用任意深度嵌套的模型(歸功于Pydantic)。

List 字段

你可以將一個(gè)屬性定義為擁有子元素的類型。例如 Python list:

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: list = []


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

這將使 tags 成為一個(gè)由元素組成的列表。不過它沒有聲明每個(gè)元素的類型。

具有子類型的 List 字段

但是 Python 有一種特定的方法來聲明具有子類型的列表:

從 typing 導(dǎo)入 List

首先,從 Python 的標(biāo)準(zhǔn)庫 typing 模塊中導(dǎo)入 List:

from typing import List, Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

聲明具有子類型的 List

要聲明具有子類型的類型,例如 list、dict、tuple:

  • 從 typing 模塊導(dǎo)入它們
  • 使用方括號(hào) [ 和 ] 將子類型作為「類型參數(shù)」傳入
from typing import List

my_list: List[str]

這完全是用于類型聲明的標(biāo)準(zhǔn) Python 語法。

對(duì)具有子類型的模型屬性也使用相同的標(biāo)準(zhǔn)語法。

因此,在我們的示例中,我們可以將 tags 明確地指定為一個(gè)「字符串列表」:

from typing import List, Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

Set 類型

但是隨后我們考慮了一下,意識(shí)到標(biāo)簽不應(yīng)該重復(fù),它們很大可能會(huì)是唯一的字符串。

Python 具有一種特殊的數(shù)據(jù)類型來保存一組唯一的元素,即 set。

然后我們可以導(dǎo)入 Set 并將 tag 聲明為一個(gè)由 str 組成的 set:

from typing import Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

這樣,即使你收到帶有重復(fù)數(shù)據(jù)的請求,這些數(shù)據(jù)也會(huì)被轉(zhuǎn)換為一組唯一項(xiàng)。

而且,每當(dāng)你輸出該數(shù)據(jù)時(shí),即使源數(shù)據(jù)有重復(fù),它們也將作為一組唯一項(xiàng)輸出。

并且還會(huì)被相應(yīng)地標(biāo)注 / 記錄文檔。

嵌套模型

Pydantic 模型的每個(gè)屬性都具有類型。

但是這個(gè)類型本身可以是另一個(gè) Pydantic 模型。

因此,你可以聲明擁有特定屬性名稱、類型和校驗(yàn)的深度嵌套的 JSON 對(duì)象。

上述這些都可以任意的嵌套。

定義子模型

例如,我們可以定義一個(gè) Image 模型:

from typing import Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Image(BaseModel):
    url: str
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    image: Optional[Image] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

將子模型用作類型

然后我們可以將其用作一個(gè)屬性的類型:

from typing import Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Image(BaseModel):
    url: str
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    image: Optional[Image] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

這意味著 FastAPI 將期望類似于以下內(nèi)容的請求體:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": ["rock", "metal", "bar"],
    "image": {
        "url": "http://example.com/baz.jpg",
        "name": "The Foo live"
    }
}

再一次,僅僅進(jìn)行這樣的聲明,你將通過 FastAPI 獲得:

  • 對(duì)被嵌入的模型也適用的編輯器支持(自動(dòng)補(bǔ)全等)
  • 數(shù)據(jù)轉(zhuǎn)換
  • 數(shù)據(jù)校驗(yàn)
  • 自動(dòng)生成文檔

特殊的類型和校驗(yàn)

除了普通的單一值類型(如 str、int、float 等)外,你還可以使用從 str 繼承的更復(fù)雜的單一值類型。

要了解所有的可用選項(xiàng),請查看關(guān)于 來自 Pydantic 的外部類型 的文檔。你將在下一章節(jié)中看到一些示例。

例如,在 Image 模型中我們有一個(gè) url 字段,我們可以把它聲明為 Pydantic 的 HttpUrl,而不是 str:

from typing import Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    image: Optional[Image] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

該字符串將被檢查是否為有效的 URL,并在 JSON Schema / OpenAPI 文檔中進(jìn)行記錄。

帶有一組子模型的屬性

你還可以將 Pydantic 模型用作 list、set 等的子類型:

from typing import List, Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image]] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

這將期望(轉(zhuǎn)換,校驗(yàn),記錄文檔等)下面這樣的 JSON 請求體:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": [
        "rock",
        "metal",
        "bar"
    ],
    "images": [
        {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        },
        {
            "url": "http://example.com/dave.jpg",
            "name": "The Baz"
        }
    ]
}

Info

請注意 images 鍵現(xiàn)在具有一組 image 對(duì)象是如何發(fā)生的。

深度嵌套模型

你可以定義任意深度的嵌套模型:

from typing import List, Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image]] = None


class Offer(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    items: List[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):
    return offer

Info

請注意 Offer 擁有一組 Item 而反過來 Item 又是一個(gè)可選的 Image 列表是如何發(fā)生的。

純列表請求體

如果你期望的 JSON 請求體的最外層是一個(gè) JSON array(即 Python list),則可以在路徑操作函數(shù)的參數(shù)中聲明此類型,就像聲明 Pydantic 模型一樣:

images: List[Image]

例如:

from typing import List

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


@app.post("/images/multiple/")
async def create_multiple_images(images: List[Image]):
    return images

無處不在的編輯器支持

你可以隨處獲得編輯器支持。

即使是列表中的元素:

如果你直接使用 dict 而不是 Pydantic 模型,那你將無法獲得這種編輯器支持。

但是你根本不必?fù)?dān)心這兩者,傳入的字典會(huì)自動(dòng)被轉(zhuǎn)換,你的輸出也會(huì)自動(dòng)被轉(zhuǎn)換為 JSON。

任意 dict 構(gòu)成的請求體

你也可以將請求體聲明為使用某類型的鍵和其他類型值的 dict。

無需事先知道有效的字段/屬性(在使用 Pydantic 模型的場景)名稱是什么。

如果你想接收一些尚且未知的鍵,這將很有用。

其他有用的場景是當(dāng)你想要接收其他類型的鍵時(shí),例如 int。

這也是我們在接下來將看到的。

在下面的例子中,你將接受任意鍵為 int 類型并且值為 float 類型的 dict:

from typing import Dict

from fastapi import FastAPI

app = FastAPI()


@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
    return weights

Tip

請記住 JSON 僅支持將 str 作為鍵。

但是 Pydantic 具有自動(dòng)轉(zhuǎn)換數(shù)據(jù)的功能。

這意味著,即使你的 API 客戶端只能將字符串作為鍵發(fā)送,只要這些字符串內(nèi)容僅包含整數(shù),Pydantic 就會(huì)對(duì)其進(jìn)行轉(zhuǎn)換并校驗(yàn)。

然后你接收的名為 weights 的 dict 實(shí)際上將具有 int 類型的鍵和 float 類型的值。

總結(jié)

使用 FastAPI 你可以擁有 Pydantic 模型提供的極高靈活性,同時(shí)保持代碼的簡單、簡短和優(yōu)雅。

而且還具有下列好處:

  • 編輯器支持(處處皆可自動(dòng)補(bǔ)全!)
  • 數(shù)據(jù)轉(zhuǎn)換(也被稱為解析/序列化)
  • 數(shù)據(jù)校驗(yàn)
  • 模式文檔
  • 自動(dòng)生成的文檔


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)