FastAPI基礎之 額外的響應模型
我們從前面的示例繼續,擁有多個相關的模型是很常見的。
對使用者模型來說尤其如此,因為:
輸入模型需要擁有密碼屬性。
輸出模型不應該包含密碼。
資料庫模型很可能需要儲存密碼的雜湊值。
Danger
永遠不要儲存使用者的明文密碼。始終儲存一個可以用於驗證的「安全雜湊值」。
如果你尚未了解該知識,你可以在安全章節中學習何為「密碼雜湊值」。
1、多個模型
下面是應該如何根據它們的密碼欄位以及使用位置去定義模型的大概思路:
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
class UserInDB(BaseModel):
username: str
hashed_password: str
email: EmailStr
full_name: Optional[str] = None
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
2、關於 **user_in.dict()
2.1 Pydantic 的 .dict()
user_in 是一個 UserIn 類的 Pydantic 模型.
Pydantic 模型具有 .dict() 方法,該方法返回一個擁有模型資料的 dict。
因此,如果我們像下面這樣建立一個 Pydantic 物件 user_in:
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
然後我們呼叫:
user_dict = user_in.dict()
現在我們有了一個資料位於變數 user_dict 中的 dict(它是一個 dict 而不是 Pydantic 模型物件)。
如果我們呼叫:
print(user_dict)
我們將獲得一個這樣的 Python dict:
{
'username': 'john',
'password': 'secret',
'email': 'john.doe@example.com',
'full_name': None,
}
2.2 解包 dict
如果我們將 user_dict 這樣的 dict 以 **user_dict 形式傳遞給一個函式(或類),Python將對其進行「解包」。
它會將 user_dict 的鍵和值作為關鍵字引數直接傳遞。
因此,從上面的 user_dict 繼續,編寫:
UserInDB(**user_dict)
會產生類似於以下的結果:
UserInDB(
username="john",
password="secret",
email="john.doe@example.com",
full_name=None,
)
或者更確切地,直接使用 user_dict 來表示將來可能包含的任何內容:
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
)
2.3 來自於其他模型內容的 Pydantic 模型
如上例所示,我們從 user_in.dict() 中獲得了 user_dict,此程式碼:
user_dict = user_in.dict()
UserInDB(**user_dict)
等同於:
UserInDB(**user_in.dict())
…因為 user_in.dict() 是一個 dict,然後我們透過以**開頭傳遞給 UserInDB 來使 Python「解包」它。
這樣,我們獲得了一個來自於其他 Pydantic 模型中的資料的 Pydantic 模型。
2.4 解包 dict 和額外關鍵字
然後新增額外的關鍵字引數 hashed_password=hashed_password,例如:
UserInDB(**user_in.dict(), hashed_password=hashed_password)
…最終的結果如下:
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
hashed_password = hashed_password,
)
Warning
輔助性的額外函式只是為了演示可能的資料流,但它們顯然不能提供任何真正的安全性。
3、減少重複
減少程式碼重複是 FastAPI 的核心思想之一。
因為程式碼重複會增加出現 bug、安全性問題、程式碼失步問題(當你在一個位置更新了程式碼但沒有在其他位置更新)等的可能性。
上面的這些模型都共享了大量資料,並擁有重複的屬性名稱和型別。
我們可以做得更好。
我們可以宣告一個 UserBase 模型作為其他模型的基類。然後我們可以建立繼承該模型屬性(型別宣告,校驗等)的子類。
所有的資料轉換、校驗、文件生成等仍將正常執行。
這樣,我們可以僅宣告模型之間的差異部分(具有明文的 password、具hashed_password 以及不包括密碼)。
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: Optional[str] = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
4、Union 或者 anyOf
你可以將一個響應宣告為兩種型別的 Union,這意味著該響應將是兩種型別中的任何一種。
這將在 OpenAPI 中使用 anyOf 進行定義。
為此,請使用標準的 Python 型別提示 typing.Union:
Note 大連做人流多少錢
定義一個 Union 型別時,首先包括最詳細的型別,然後是不太詳細的型別。在下面的示例中,更詳細的 PlaneItem 位於 Union[PlaneItem,CarItem] 中的 CarItem 之前。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type = "car"
class PlaneItem(BaseItem):
type = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]
5、模型列表
你可以用同樣的方式宣告由物件列表構成的響應。為此,請使用標準的 Python typing.List:
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/", response_model=List[Item])
async def read_items():
return items
6、任意 dict 構成的響應
你還可以使用一個任意的普通 dict 宣告響應,僅宣告鍵和值的型別,而不使用 Pydantic 模型。
如果你事先不知道有效的欄位/屬性名稱(對於 Pydantic 模型是必需的),這將很有用。
在這種情況下,你可以使用 typing.Dict:
from typing import Dict
from fastapi import FastAPI
app = FastAPI()
@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2770176/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- FastAPI基礎之 表單和檔案操作ASTAPI
- 【FastAPI】入門基礎ASTAPI
- vue響應式基礎Vue
- FastAPI 學習之路(十二)介面幾個額外資訊和額外資料型別ASTAPI資料型別
- FastAPI - Tortoise ORM 資料庫基礎操作ASTAPIORM資料庫
- 前端響應式佈局基礎——rem前端REM
- JavaWeb基礎(day15)( http + tomcat + servlet + 響應)JavaWebHTTPTomcatServlet
- Django基礎之六(模型理論知識)Django模型
- Java 併發基礎之記憶體模型Java記憶體模型
- 精講響應式webclient第1篇-響應式非阻塞IO與基礎用法Webclient
- Django基礎五之django模型層(二)多表操作Django模型
- 微服務架構設計基礎之立方體模型微服務架構模型
- Django基礎五之django模型層(一)單表操作Django模型
- Java記憶體模型的基礎Java記憶體模型
- 前端基礎之jQuery基礎前端jQuery
- Spring原始碼解析之基礎應用(二)Spring原始碼
- Spring原始碼解析之基礎應用(三)Spring原始碼
- vue面試題(vue2響應式資料基礎)Vue面試題
- 響應式程式設計基礎教程:Spring Boot 與 Lettuce 整合程式設計Spring Boot
- 『動善時』JMeter基礎 — 29、JMeter響應斷言詳解JMeter
- 資料庫應有與之匹配的基礎環境資料庫
- 啃碎併發(九):記憶體模型之基礎概述記憶體模型
- 機率圖模型基礎模型
- 談談JVM(基礎模型)JVM模型
- 公共基礎知識-模型模型
- Javascript基礎之-thisJavaScript
- nginx的基礎應用(續)Nginx
- 前端之路---入坑篇之基礎中的基礎html前端HTML
- Swift之SQLite的基礎使用SwiftSQLite
- SpringBoot之:SpringBoot的HATEOAS基礎Spring Boot
- 0-目標檢測模型的基礎模型
- FastAPI的路由ASTAPI路由
- vue基礎-動態樣式&表單繫結&vue響應式原理Vue
- elf,基於flexbox的響應式CSS框架FlexCSS框架
- Java應用伺服器之tomcat基礎配置(一)Java伺服器Tomcat
- DRF之請求與響應
- Golang 基礎之基礎語法梳理 (三)Golang
- echarts基礎應用Echarts