(三)FastAPI 的数据验证与序列化
在现代 Web 开发中,数据验证和序列化是不可或缺的部分。FastAPI 通过集成 Pydantic,为数据验证和序列化提供了强大且易用的功能。本文将详细介绍如何在 FastAPI 中进行数据验证和序列化,帮助你达到高级程序员的水平。
1. Pydantic 简介
Pydantic(/paɪˈdæntɪk/)
是一个数据验证和解析库,基于 Python 类型提示。它允许你通过定义数据模型,自动进行数据验证和解析。Pydantic 的主要特性包括:
- 类型提示支持:使用标准的 Python 类型提示。
- 数据验证:自动验证传入的数据,并提供详细的错误信息。
- 数据解析:自动将数据解析为定义的类型。
2. 使用 Pydantic 进行数据验证
在 FastAPI 中,Pydantic 模型通常用于请求体、响应体以及路径参数和查询参数的验证。以下是一些具体的用法示例。
定义 Pydantic 模型:
from pydantic import BaseModel, Field
from typing import Optional
class Item(BaseModel):
name: str
description: Optional[str] = Field(None, title="The description of the item", max_length=300)
price: float = Field(..., gt=0, description="The price must be greater than zero")
tax: Optional[float] = None
示例解析:
name
: 必填字段,类型为 str。description
: 可选字段,类型为 str,默认值是None
,并添加了字段说明和最大长度限制。price
: 必填字段,类型为 float,并添加了大于零的验证。tax
: 可选字段,类型为 float,默认值是None
。
3. 请求体数据验证
示例:创建一个包含请求体的路由
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
@app.post("/items/")
async def create_item(item: Item):
return item
在这个示例中,create_item
路由会接收一个Item
类型的请求体。FastAPI 会自动将请求体的数据解析并验证为Item
类型,如果验证失败,会自动返回一个详细的错误响应。
HTTP 状态码 422 代表 "Unprocessable Entity"(无法处理的实体)。这是一个 WebDAV 扩展状态码,表示服务器理解请求的内容类型,并且请求的语法也是正确的,但是服务器无法处理所包含的指令。在 FastAPI 中,状态码 422 通常出现在请求数据验证失败的情况下。FastAPI 使用 Pydantic 来验证请求数据,如果传入的数据不符合预期的格式或规则,FastAPI 会返回一个 422 状态码,并包含详细的错误信息。
4. 响应体数据验证与序列化
示例:定义响应模型
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
class ItemResponse(BaseModel):
item: Item
message: str
@app.post("/items/", response_model=ItemResponse)
async def create_item(item: Item):
return {"item": item, "message": "Item created successfully"}
在这个示例中,create_item
路由返回的数据会被自动验证和序列化为ItemResponse
类型。如果返回的数据不符合ItemResponse
模型定义,FastAPI 会自动返回一个错误响应。
5. 路径参数和查询参数的数据验证
示例:验证路径参数和查询参数
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
@app.get("/items/{item_id}")
async def read_item(item_id: int = Path(..., gt=0, description="The ID of the item to get"), q: Optional[str] = Query(None, max_length=50)):
return {"item_id": item_id, "q": q}
在这个示例中,item_id
是一个路径参数,并且被验证为大于 0。q
是一个查询参数,最大长度为50。FastAPI 会自动进行这些验证,并返回相应的错误信息。
6. 高级用法
复杂嵌套模型
- Pydantic 支持复杂嵌套模型,使得你可以创建更复杂的数据结构。
from pydantic import BaseModel
from typing import List, Optional
class SubItem(BaseModel):
name: str
price: float
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
subitems: List[SubItem]
@app.post("/items/")
async def create_item(item: Item):
return item
联合类型 (Union) 和自定义验证器
- Pydantic 还支持使用联合类型 (Union) 和自定义验证器。
from pydantic import BaseModel, validator, ValidationError
from typing import Union
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
@validator("price")
def check_price(cls, value):
if value <= 0:
raise ValueError("Price must be greater than zero")
return value
class DiscountedItem(BaseModel):
item: Item
discount: Union[float, int]
@app.post("/discounted-items/")
async def create_discounted_item(discounted_item: DiscountedItem):
return discounted_item
处理复杂数据
- 当你需要处理复杂数据时,Pydantic 可以帮助你简化代码并保证数据的正确性。
from pydantic import BaseModel, ValidationError
from typing import List
class User(BaseModel):
id: int
name: str
friends: List[int]
class Post(BaseModel):
id: int
title: str
content: str
author: User
@app.post("/posts/")
async def create_post(post: Post):
return post
7. 错误处理与自定义错误信息
当数据验证失败时,FastAPI 会返回详细的错误信息。你可以自定义这些错误信息来提供更好的用户体验。
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
price: float = Field(..., gt=0, description="The price must be greater than zero")
@app.post("/items/")
async def create_item(item: Item):
try:
item = Item(**item.dict())
except ValidationError as e:
raise HTTPException(status_code=400, detail=e.errors())
return item
通过深入了解和掌握 FastAPI 的数据验证和序列化功能,你可以更高效地开发和维护你的 Web 应用。Pydantic 的强大功能使得数据验证和解析变得简洁而高效,结合 FastAPI 的自动文档生成和类型提示支持,你可以创建出性能优越且易于维护的 API。
希望这篇文章能帮助你更深入地理解和使用 FastAPI,实现更高级的编程技巧和实践。
转载自:https://juejin.cn/post/7379074566032752677