使用 FastAPI,你可以定義、校驗(yàn)、記錄文檔并使用任意深度嵌套的模型(歸功于Pydantic)。
你可以將一個(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è)元素的類型。
但是 Python 有一種特定的方法來聲明具有子類型的列表:
首先,從 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、dict、tuple:
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
但是隨后我們考慮了一下,意識(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 獲得:
除了普通的單一值類型(如 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。
無需事先知道有效的字段/屬性(在使用 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 類型的值。
使用 FastAPI 你可以擁有 Pydantic 模型提供的極高靈活性,同時(shí)保持代碼的簡單、簡短和優(yōu)雅。
而且還具有下列好處:
更多建議: