FastAPI(19)- Response Model 響應模型
阿新 • • 發佈:2022-01-05
FastAPI(19)- Response Model 響應模型
前言
- 前面文章寫的這麼多路徑函式最終 return 的都是自定義結構的字典
- FastAPI 提供了 response_model 引數,宣告 return 響應體的模型
什麼是路徑操作、路徑函式
# 路徑操作
@app.post("/items/", response_model=Item)
# 路徑函式
async def create_item(item: Item):
...
重點
response_model 是路徑操作的引數,並不是路徑函式的引數哦
- @app.get()
- @app.post()
- @app.put()
- @app.delete()
最簡單的栗子
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog: https://www.cnblogs.com/poloyy/
# time: 2021/9/21 5:12 下午
# file: 17_response_model.py
"""
from typing import List, Optional
import uvicorn
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.post("/items/", response_model=Item)
async def create_item(item: Item):
return item
if __name__ == "__main__":
uvicorn.run(app="16_Header:app" , host="127.0.0.1", port=8080, reload=True, debug=True)
上面程式碼栗子,請求模型和響應模型都是同一個 Pydantic Model
FastAPI 通過 response_model 會做
- 將輸出資料轉換為 Model 中宣告的型別
- 驗證資料
- 在 OpenAPI 給 Response 新增 JSON Schema 和 Example Value
- 最重要:將輸出資料限制為 model 的資料
正確傳參的請求結果
檢視 Swagger API 文件
為什麼 response_model 不是路徑函式引數而是路徑操作引數呢?
- 因為路徑函式的返回值並不是固定的,可能是 dict、資料庫物件,或其他模型
- 但是使用響應模型可以對響應資料進行欄位限制和序列化
區分請求模型和響應模型的栗子
需求
- 假設一個註冊功能
- 輸入賬號、密碼、暱稱、郵箱,註冊成功後返回個人資訊
- 正常情況下不應該返回密碼,所以請求體和響應體肯定是不一樣的
實際程式碼
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Optional[str] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user
- 即使請求資料包含了密碼,但因為響應模型不包含 password,所以最終返回的響應資料也不會包含 password
- FastAPI 通過 Pydantic 過濾掉所有未在響應模型中宣告的資料
正確傳參的請求結果
檢視 Swagger API 文件
來看看路徑操作有什麼關於響應模型的引數
response_model_exclude_unset
作用
- 有時候資料會有預設值,比如資料庫中設定了預設值,不想返回這些預設值怎麼辦?
- response_model_exclude_unset=True設定該引數後就不會返回預設值,只會返回實際設定的值,假設沒設定值,則不返回該欄位
實際程式碼
class Item(BaseModel):
name: str
price: float
# 下面三個欄位有預設值
description: Optional[str] = None
tax: float = 10.5
tags: List[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
# 從上面 items 字典中,根據 item_id 取出對應的值並返回
return items[item_id]
item_id=foo 的請求結果
不會返回有預設值的欄位
item_id=bar 的請求結果
只返回了設定值的欄位
item_id=baz 的請求結果
- 五個欄位都有設定值,所有都包含在響應資料中了
- 即使 description、tax、tags 設定的值和預設值是一樣的,FastAPI 仍然能識別出它們是明確設定的值,所以會包含在響應資料中
response_model_include、response_model_exclude
作用
- include:包含
- exclude:排除
- 其實就是響應模型只要包含/排除有些屬性
引數資料型別
- 從上面可以看到,這兩個引數的型別都是Optional[Union[SetIntStr, DictIntStrAny]]
- Optional:可選
- Union:聯合型別
- 既可以是 SetIntStr,也可以是 DictIntStrAny,滿足其一即可
SetIntStr、DictIntStrAny
檢視原始碼可以看到
# set 型別,子元素型別可以是 int、str
SetIntStr = Set[Union[int, str]]
# dict 型別,鍵型別可以是 int、str,值型別可以是任意型別
DictIntStrAny = Dict[Union[int, str], Any]
官方建議
- 不推薦使用這兩個引數,而推薦使用上面講到的思想,通過多個類來滿足請求模型、響應模型
- 因為在 OpenAPI 文件中可以看到 Model 完整的 JSON Schema
response_model_include的栗子
結合上面註冊功能的栗子:請求要密碼,響應不要密碼
class User(BaseModel):
username: str
password: str
email: EmailStr
full_name: Optional[str] = None
@app.post("/user/", response_model=User, response_model_include={"username", "email", "full_name"})
async def create_user(user: User):
return user
正確傳參的請求結果
檢視 Swagger API 文件
passwor 仍然存在,這明顯不是我們想要的最佳效果,所以還是推薦用多個類的思想
response_model_exclude的栗子
class User(BaseModel):
username: str
password: str
email: EmailStr
full_name: Optional[str] = None
@app.post("/user/", response_model=User, response_model_exclude={"password"})
async def create_user(user: User):
return user
正確傳參的請求結果請求結果
同 include
檢視 Swagger API 文件
同 include