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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM