Pydantic 学习与使用
Pydantic 学习与使用
在 Fastapi 的 Web 开发中的数据验证通常都是在使用 Pydantic 来进行数据的校验,本文将对 Pydantic 的使用方法做记录与学习。
**简介:**Pydantic 是一个在 Python 中用于数据验证和解析的第三方库,它现在是 Python 使用最广泛的数据验证库。它利用声明式的方式定义数据模型和Python 类型提示的强大功能来执行数据验证和序列化,使您的代码更可靠、更可读、更简洁且更易于调试。它还可以从模型生成 JSON 架构,提供了自动生成文档等功能,从而轻松与其他工具集成。
参考文章:
作者:暴走的海鸽
链接:https://juejin.cn/post/7395080141130039305
1. Pydantic 快速上手
# 安装
pip install pydantic# 使用 email 验证的时候需要额外安装
pip install pydantic[email]
Pydantic 使用起来简单直观,需要最少的样板代码和配置。它适用于许多流行的 IDE 和静态分析工具,例如 PyCharm、VS Code、mypy 等。Pydantic 可以轻松与其他流行的 Python 库(如 Flask、Django、FastAPI 和 SQLAlchemy)集成,使其易于在现有项目中使用。
Pydantic 使用类型注解来定义模型的字段类型,以确保确保数据符合预期的类型和格式。你可以使用Python 内置的类型、自定义类型或者其他Pydantic 提供的验证类型。
Pydantic 提供了从各种数据格式(例如 JSON、字典)到模型实例的转换功能。它可以自动将输入数据解析成模型实例,并保留类型安全性和验证规则。
Pydantic 的核心验证逻辑是用 Rust 编写的,使其成为 Python 中最快的数据验证库之一。它还支持延迟验证和缓存,以提高效率。
1.1 数据验证
Pydantic 的核心验证逻辑是用 Rust 编写的,使其成为 Python 中最快的数据验证库之一。它还支持延迟验证和缓存,以提高效率。然后,您可以使用类型注释定义模型的属性,并选择性地提供默认值或验证器。
from enum import Enum
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, conint, EmailStr, constrclass GenderEnum(str, Enum):"""性别类的枚举, 使用多继承创建;"""male = "男"female = "女"class User(BaseModel):"""继承的基类;"""id: intname: strage: conint(ge=0, le=100) # 使用 Pydantic 限制数字范围;gender: GenderEnumemail: EmailStr # 使用 Pydantic 的邮件约束来限制约束;signup_ts: Optional[datetime] = Nonepassword: constr(min_length=8, max_length=16)if __name__ == '__main__':user_data = {"id": 1,"name": "傻狗","age": 18,"gender": GenderEnum.male,"email": "123456788@qq.com","signup_ts": datetime.now(),"password": "<PASSWORD>",}user = User.model_validate(user_data)print(user)print(f"User id: {user.id}, User name: {user.name}, User email: {user.email}")"""
>>> 输出:
id=1 name='傻狗' age=18 gender=<GenderEnum.male: '男'> email='123456788@qq.com' signup_ts=datetime.datetime(2025, 5, 24, 14, 25, 6, 493690) password='<PASSWORD>'
User id: 1, User name: 傻狗, User email: 123456788@qq.com
"""
上述的代码就是针对字典中的数据完成数据的校验;
当我们的校验需求比较复杂的时候,我们就可以自己定义比较复杂的校验函数进行使用
from enum import Enum
from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel, conint, EmailStr, constr, field_validatorclass GenderEnum(str, Enum):"""性别类的枚举, 使用多继承创建;"""male = "男"female = "女"def check_name(name: str) -> str:""":param name::return:"""if not name.startswith("小"): # 检查字符串是否以特定字符开头raise ValueError("must be startswith 小")return nameclass User(BaseModel):"""继承的基类;"""id: intname: strage: conint(ge=0, le=100) # 使用 Pydantic 限制数字范围;# gender: GenderEnumemail: EmailStr # 使用 Pydantic 的邮件约束来限制约束;signup_ts: Optional[datetime] = None# password: constr(min_length=8, max_length=16)friends: List[str] = []validate_fields = field_validator("name")(check_name)@field_validator("age")@classmethod # 装饰器的顺序不要放错, 否则可能不生效;def check_age(cls, age: int):if age < 18:raise ValueError("age must be >= 18")return ageif __name__ == '__main__':user_data = {"id": 123,"name": "小卤蛋","age": 28, # 小于18 就会报错;"email": "xiaoludan@example.com",'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],}user = User(**user_data)print(user.age) # 取出模型中的数据print(user.model_dump()) # 字典的形式输出;
**特别注意:**Pydantic 是强制的校验,不满足的时候程序会进行报错,注意和泛型进行区分;
上述的代码,我们是一个字段的进行的校验,那么我们能不能一次校验多个字段呢?
from datetime import datetime
from typing import List, Optional
from typing_extensions import Self # 如果python版本不低于3.11,则可以直接从typing中导入Self
from pydantic import BaseModel, ValidationError, EmailStr, field_validator, model_validatordef check_name(v: str) -> str:"""Validator to be used throughout"""if not v.startswith("小"):raise ValueError("must be startswith 小")return vclass User(BaseModel):id: intname: str = "小卤蛋"age: intemail: EmailStrsignup_ts: Optional[datetime] = Nonefriends: List[str] = []validate_fields = field_validator("name")(check_name)@field_validator("age")@classmethoddef check_age(cls, age):if age < 18:raise ValueError("用户年龄必须大于18岁")return age@model_validator(mode="after") # after 模式表示是所有字段完成验证之后再进行额外的验证;def check_age_and_name(self) -> Self:if self.age < 30 and self.name != "小卤蛋":raise ValueError("用户年龄必须小于30岁, 且名字必须为小卤蛋")return selfif __name__ == '__main__':user_data = {"id": 123,"name": "小xi卤蛋","age": 20,"email": "xiaoludan@example.com",'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],}try:user = User(**user_data)print(user.model_dump())except ValidationError as e:print(f"Validation error: {e.json()}")
上述的代码会同时对age
和name
字段进行验证,使用的是装饰器model_validator
;
额外补充:上述的代码中用到了Enum枚举类,枚举类是一种特殊的类,用于定义一组固定的常量。在编程中,我们经常需要表示一些有限的、固定的状态或者选项。例如,一周的星期几(星期一、星期二……星期日),或者一个交通信号灯的状态(红灯、黄灯、绿灯)。使用枚举类可以清晰地表示这些固定的状态,避免使用容易出错的字符串或者整数来表示。
-
创建枚举类
# Enum 是 Python 的标准库 enum 模块中的一个类,是创建枚举类的基础。 from enum import Enumclass Color(Enum):""" 枚举类;"""RED = 1GREEN = 2BLUE = 3
-
枚举类的基本属性和方法
-
name 属性,表示枚举成员的名称
print(Color.RED.name) # 输出 "RED"
-
value
属性:表示枚举成员的值。print(Color.RED.value) # 输出 1
-
__members__
属性:返回一个包含枚举类中所有成员的字典,键是成员名称,值是成员本身。for name, member in Color.__members__.items():print(name, member)""" RED Color.RED GREEN Color.GREEN BLUE Color.BLUE """
-
__iter__
方法:可以对枚举类进行迭代,迭代的是枚举成员。for color in Color:print(color)""" Color.RED Color.GREEN Color.BLUE """
-
-
枚举类的应用场景
在开发软件时,很多对象都有状态。例如,一个订单的状态可以是“已下单”“已支付”“已发货”“已完成”等。使用枚举类来表示这些状态可以避免使用字符串或者整数来直接表示状态,减少错误。当需要从一组固定的选项中选择时,枚举类也很有用。比如在一个图形界面程序中,用户可以选择不同的字体样式,这些字体样式可以用枚举类来表示。使用枚举类可以使代码更清晰。例如,用枚举类表示星期几,相比直接使用数字或者字符串,代码更容易理解。
model_validator 是 Pydantic 中的一个装饰器,用于在模型实例创建后进行验证。它允许开发者在模型的所有字段都被解析和验证之后,执行额外的验证逻辑。这个装饰器可以用于确保模型的多个字段之间的关系或其他复杂的验证条件。
from typing import Annotatedfrom pydantic import BaseModel, Field, validate_callclass Person(BaseModel):name: str = Field(..., min_length=1, max_length=100)age: int = Field(..., gt=0, lt=20)# @validate_call
def greet(person: Person, message: Annotated[str, Field(min_length=1, max_length=100)]):print(f"Hello, {person.name}! {message}")# 正确的调用
greet(Person(name="公众号", age=18), "How are you?")
greet(Person(name="公众号", age=18), 1) # 不使用装饰器会运行,但是与类型不符, 使用 @ 装饰器后会报错;
然而,我们通常是希望定义和使用要符合我们的预期,以避免不可预见的错误。
此时validate_call
装饰器就可以很好的为我们实现这一需求。
1.2 计算属性
核心的装饰器: @computed_field # 计算属性 @property 被装饰函数以值的形式返回;
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, ValidationError, EmailStr, computed_fieldclass User(BaseModel):id: intname: str = "小卤蛋"age: intemail: EmailStrsignup_ts: Optional[datetime] = Nonefriends: List[str] = []@computed_field # 计算属性@propertydef link(self) -> str:return f"尼古拉斯 · {self.name}"if __name__ == '__main__':user_data = {"id": 123,"name": "小卤蛋","age": 20,"email": "xiaoludan@example.com",'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],}#try:user = User(**user_data)print(f"{user.model_dump()} .... type: {type(user.model_dump())}")except ValidationError as e:print(f"Validation error: {e.json()}")
当使用装饰link 属性会跟随着结果一起显示出来,
2. Pydantic 配置管理
# 安装依赖
pip install pydantic_settings
2.1 直接设置
pydantic_settings
可以很好的管理服务中的配置信息;使用的时候继承 BaseSettings 可以直接从环境变量中读取相对应的配置信息,也可以以手动填入的方式进行;
import os# 导入需要的配置;
from pydantic import HttpUrl, Field
from pydantic_settings import BaseSettings# 初始化环境变量
os.environ['DATABASE_HOST'] = "http://baidu.com"
os.environ['DATABASE_USER'] = "公众号:海哥python"
os.environ['DATABASE_PASSWORD'] = "123456abcd"
os.environ['API_KEY'] = "DHKSDsdh*(sdds"class AppConfig(BaseSettings):"""应用配置类, 用来管理应用程序的配置信息;"""# 定义配置项# 定义 url 形式的配置;DATABASE_HOST: HttpUrl# 定义配置项database_user,类型为字符串,默认最小长度为5DATABASE_USER: str = Field(min_length=5)# 定义配置项database_password,类型为字符串,默认最小长度为10DATABASE_PASSWORD: str = Field(min_length=10)# 定义配置项api_key,类型为字符串,默认最小长度为8API_KEY: str = Field(min_length=8)# 打印配置类的实例化对象的模型信息,用于调试和确认配置的正确性
print(AppConfig().model_dump())
2.2 配置文件
在代码的同级目录下创建一个.env
的配置文件;
DATABASE_HOST=http://baidu.com
DATABASE_USER=公众号:海哥python
DATABASE_PASSWORD=123456abcd
API_KEY=DHKSDsdh*(sdds
代码变化不大, 只有加载的部分发生一些变化;
# 导入需要的配置;
from pydantic import HttpUrl, Field
from pydantic_settings import BaseSettings, SettingsConfigDictclass Settings(BaseSettings):"""定义模型的基本类;"""# 定义配置模型的设置,包括.env文件位置、编码、大小写敏感性和额外参数策略model_config = SettingsConfigDict(env_file=".env",env_file_encoding="utf-8",case_sensitive=False,extra="forbid")# 数据库主机的URL,必须是一个有效的HTTP或HTTPS URLdatabase_host: HttpUrl# 数据库用户的名称,最小长度为5个字符database_user: str = Field(min_length=5)# 数据库用户的密码,最小长度为10个字符database_password: str = Field(min_length=10)# API的密钥,最小长度为8个字符api_key: str = Field(min_length=8)if __name__ == '__main__':# 打印配置类的实例化对象的模型信息,用于调试和确认配置的正确性print(Settings().model_dump())
3. Pydantic 高级应用
3.1 数据嵌套
Pydantic 支持嵌套数的数据模型,方便管理复杂的数据结构。
from typing import List
from pydantic import BaseModel, conintclass Friend(BaseModel):name: strage: conint(gt=0, le=99)class User(BaseModel):name: strage: conint(gt=0, le=99)friends: List[Friend] # 设置字段嵌套 Friend 类.if __name__ == '__main__':# 创建并验证数据user_data = {'name': '三体-章北海','age': 30,# 设置嵌套, 'friends': [{'name': '小卤蛋', 'age': 3}, {'name': '李元芳', 'age': 18}]}user = User(**user_data)print(user)
3.2 Filed 的使用
Pydantic 的Field
函数是一个强大的工具,它允许你在模型字段上设置额外的验证规则和默认值。Field
函数通常与模型字段一起使用,以提供更多的定制选项。
参数 | 具体含义 |
---|---|
... | 表示该字段是必填项 |
default | 用于定义字段的默认值 |
default_factory | 用于定义字段的默认值函数 |
alias | 字段定义别名 |
validation_alias | 字段定义别名,只想将别名用于验证 |
serialization_alias | 字段定义别名,只想定义用于序列化的别名 |
gt 、lt 、ge 等 | 约束数值,大于、小于、大于或等于 等 |
min_length 、max_length 等 | 约束字符串 |
min_items 、max_items 等 | 元组、列表或集合约束 |
validate_default | 控制是否应验证字段的默认值,默认情况下,不验证字段的默认值。 |
strict | 指定是否应在“严格模式”下验证字段 |
frozen | 用于模拟冻结的数据类行为 |
exclude | 用于控制导出模型时应从模型中排除哪些字段 |
pattern | 对于字符串字段,您可以设置为 pattern 正则表达式以匹配该字段所需的任何模式。 |
示例代码:
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, Field, EmailStr, ValidationError, SecretStrclass User(BaseModel):id: int = Field(..., alias="_id", frozen=True, strict=True)name: str = Field(default="小卤蛋", min_length=1, max_length=100) # 设置默认值,使用 min_length 和 max_length 来限制字符串长度age: int = Field(gt=0) # 支持各类条件验证,这里假设年龄必须大于0email: EmailStrsignup_ts: Optional[datetime] = Field(default_factory=datetime.now, nullable=False, validate_default=True)friends: List[str] = Field(default=[], min_items=0)passwd: SecretStr = Field(min_length=6, max_length=20, exclude=True) # passwd不会被序列化if __name__ == '__main__':print(User.model_json_schema())user_data = {"_id": 123, # 使用别名 _id"name": "小卤蛋","age": 20,"email": "xiaoludan@example.com",# 'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],"passwd": "123456"}try:user = User(**user_data)print(f"创建用户: {user}")print(f"转成字典形式: {user.model_dump()} .... type: {type(user.model_dump())}")print(f"转成json格式:{user.model_dump_json()} .... type: {type(user.model_dump_json())}")print(f"用户属性: User id: {user.id}, User name: {user.name}, User email: {user.email}")# user.id = 456 # 这里修改会报错except ValidationError as e:print(f"Validation error: {e.json()}")
3.3 Config 配置
如果要对BaseModel中的某一基本型进行统一的格式要求,我们还可以使用Config类来实现。以下是一些 Config 类中常见的属性及其含义:
参数 | 取值类型 | 具体含义 |
---|---|---|
str_min_length | int | str 类型的最小长度,默认值为None |
str_max_length | int | str 类型的最大长度。默认值为None |
extra | str | 在模型初始化期间是否忽略、允许或禁止额外的属性。默认值为 ‘ignore’。allow - 允许任何额外的属性。forbid - 禁止任何额外的属性。ignore - 忽略任何额外的属性。 |
frozen | bool | 模型是否可变 |
str_to_upper | bool | 是否将 str 类型的所有字符转换为大写。默认值为 False 。 |
str_strip_whitespace | bool | 是否去除 str 类型的前导和尾随空格。 |
str_to_lower | bool | 是否将 str 类型的所有字符转换为小写。默认值为 False 。 |
#! -*-conding: UTF-8 -*-from pydantic import BaseModelclass User(BaseModel):name: strage: intclass Config:str_min_length = 10 # 字符串最小长度str_max_length = 20 # 字符串最大长度user = User(name="John Doe", age=30) # 此时字段不满足约束会报错;
3.4 数据序列化
使用模型类
.model_dump()
方法可以将一个模型类型实例对象转换为字典类型的数据。
#! -*-conding: UTF-8 -*-
# @公众号: 海哥python
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, ValidationError, EmailStr, field_validator, field_serializer
from enum import Enumclass GenderEnum(str, Enum):"""性别枚举"""male = "男"female = "女"class User(BaseModel):id: intname: str = "小卤蛋"age: intemail: EmailStrsignup_ts: Optional[datetime] = datetime.now()friends: List[str] = []sex: GenderEnum@field_validator("age") # 装饰器的顺序不能变化;@classmethoddef check_age(cls, age):if age < 18:raise ValueError("用户年龄必须大于18岁")return age@field_serializer('signup_ts', when_used="always")def serialize_signup_ts(self, value: datetime) -> str:"""默认情况下, datetime 对象被序列化为 ISO 8601 字符串。这里使用field_serializer自定义序列化规则。"""return value.strftime('%Y-%m-%d %H:%M:%S')@field_serializer('sex', when_used="always")def serialize_sex(self, value) -> str:return value.valueif __name__ == '__main__':user_data = {"id": 123,"name": "小卤蛋","age": 20,"email": "xiaoludan@example.com",# 'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],"sex": "男",}try:user = User.model_validate(user_data)print(f"{user.model_dump()} .... type: {type(user.model_dump())}")except ValidationError as e:print(f"Validation error: {e.json()}")
使用模型类的
.model_dump_json()
方法可以将一个模型的实例转换成为 JSON 字符串。
from datetime import datetime
from typing import List, Optional, Any
from pydantic import BaseModel, ValidationError, EmailStr, field_validator, field_serializer, model_serializerclass User(BaseModel):id: intname: str = "小卤蛋"age: intemail: EmailStrsignup_ts: Optional[datetime] = datetime.now()friends: List[str] = []@field_validator("age")@classmethoddef check_age(cls, age):if age < 18:raise ValueError("用户年龄必须大于18岁")return age@field_serializer('signup_ts', when_used="json")def serialize_signup_ts(self, value: datetime) -> str:return value.strftime('%Y-%m-%d %H:%M:%S')@model_serializer(when_used="json")def serialize_model(self) -> dict[str, Any]:return {'id': self.id,'name': self.name,'age': self.age + 1,'email': self.email,'signup_ts': self.serialize_signup_ts(self.signup_ts),'friends': self.friends,}if __name__ == '__main__':user_data = {"id": 123,"name": "小卤蛋","age": 20,"email": "xiaoludan@example.com",# 'signup_ts': '2024-07-19 00:22','friends': ["公众号:海哥python", '小天才', b''],}try:user = User.model_validate(user_data)print(f"{user.model_dump_json()} .... type: {type(user.model_dump_json())}")print(f"{user.model_dump()} .... type: {type(user.model_dump())}")except ValidationError as e:print(f"Validation error: {e.json()}")
也可以使用model_serializer
对整体模型的序列化做定制。结果如下:
"""
{"id":123,"name":"小卤蛋","age":21,"email":"xiaoludan@example.com","signup_ts":"2024-07-24 14:17:42","friends":["公众号:海哥python","小天才",""]} .... type: <class 'str'>
{'id': 123, 'name': '小卤蛋', 'age': 20, 'email': 'xiaoludan@example.com', 'signup_ts': datetime.datetime(2024, 7, 24, 14, 17, 42, 45474), 'friends': ['公众号:海哥python', '小天才', '']} .... type: <class 'dict'>
"""
3.5 文档生成
Pydantic 可以自动生成 API 文档。
#! -*-conding: UTF-8 -*-from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, EmailStr, field_validatorclass User(BaseModel):id: intname: str = "小卤蛋"age: intemail: EmailStrsignup_ts: Optional[datetime] = Nonefriends: List[str] = []@field_validator("age")def check_age(cls, age):if age < 18:raise ValueError("用户年龄必须大于18岁")return ageif __name__ == '__main__':print(User.model_json_schema())
通过model_json_schema
方法可以得到API文档。
4. Fastapi 中的 Pydantic
在 FastAPI 中,与普通的程序相同,可以通过定义 Pydantic 模型来指定请求参数的结构和类型。以下是一个简单的例子:
""" 定义参数模型;
"""from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = None
在 Fastapi 中,你可以将 Pydantic 模型作为函数参数,Fastapi 会自动解析请求中的 json 数据,并将其转换成为 Pydantic 模型实例。如果数据不符合模型定义,FastApi 会自动返回一个 422 错误。
import uvicorn
from fastapi import FastAPI, Request, Form
from fastapi.params import Depends
from pydantic import BaseModel
from watchfiles import awatchapp = FastAPI(title="测试小Demo",description="文档描述",version="1.0",
)class QueryParam(BaseModel):q: str | None = Nonelimit: int = 10offset: int = 0def get_query_params(params: QueryParam = Depends()):print(params)return params@app.get("/query", tags=["query"])
async def query(params: QueryParam = Depends(get_query_params)):return {"params": params}@app.get("/filter", tags=["filter"])
async def my_filter(params: QueryParam):print(params)return paramsif __name__ == '__main__':uvicorn.run(app, host="127.0.0.1", port=8000)
上述返回的就是 422 错误表明,没有通过校验。
上述的函数并没有指定通过那种方式指定解析数据,如果不显式指定 Body
或 Query
,FastAPI 会根据参数的位置和类型自动推断参数的来源:
- 如果参数是函数的路径参数(即在路径中定义的参数),则会从路径中提取。
- 如果参数是函数的普通参数(非路径参数),且没有显式指定
Body
或Query
,则会根据参数的类型来推断:- 如果参数是复杂类型(如 Pydantic 模型),则会从请求体中提取。
- 如果参数是简单类型(如
str
、int
等),则会从查询字符串中提取。
4.1 设置校验规则
from pydantic import BaseModel, Fieldclass Item(BaseModel):name: str = Field(..., min_length=3)description: str = Field(None, max_length=100)price: float = Field(..., gt=0, le=100)tax: float = Field(None, ge=0, le=100)"""
min_length=3:name 的长度至少为 3。
max_length=100:description 的长度最多为 100。
gt=0:price 必须大于 0。
le=100:price 必须小于或等于 100。
ge=0:tax 必须大于或等于 0。
le=100:tax 必须小于或等于 100。
"""
4.2 自定义校验方法
可以使用@validator
装饰器来定义自定义校验方法。
from pydantic import BaseModel, validatorclass Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = None@validator("price")def check_price(cls, v):if v < 0:raise ValueError("price must be greater than 0")return v
4.3 路径参数和查询参数
Pydantic 模型不仅可以用于请求体,还可以用于查询参数和路径参数。例如:
from fastapi import FastAPI, Query
from pydantic import BaseModelapp = FastAPI()class QueryParams(BaseModel):query: str = Query(..., min_length=3, max_length=50)@app.get("/items/")
async def get_items(query_params: QueryParams):return {"query": query_params.query}
在这个例子中,query_params
是一个 QueryParams
类型的 Pydantic 模型,它定义了一个查询参数 query
。FastAPI 会自动解析查询参数,并将其转换为 QueryParams
实例。
4.4 响应模型
可以使用 Pydantic 模型来定义响应数据的结构。例如:
import uvicorn
from fastapi import FastAPI, Request, Form
from fastapi.params import Depends
from pydantic import BaseModel
from watchfiles import awatchapp = FastAPI(title="测试小Demo",description="文档描述",version="1.0",
)class Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = None@app.post("/items/", response_model=Item)
async def create_item(item: Item):return itemif __name__ == '__main__':uvicorn.run(app, host="127.0.0.1", port=8000)
在这个例子中,response_model=Item
表示响应数据的结构将遵循 Item
模型的定义。FastAPI 会自动将返回的数据转换为 Item
实例,并确保其符合模型定义。
4.5 结合 Depends
Pydantic
和 Depends
可以结合使用,以实现更强大的参数校验和依赖注入功能。
-
模型校验
Depends
主要用于声明依赖,例如获取数据库连接、验证用户身份等。而Pydantic
模型则用于数据验证和转换。你可以将Pydantic
模型作为依赖函数的返回值,这样就可以在路由函数中直接使用经过校验的数据。# !/usr/bin/env python # -*-coding:utf-8 -*-""" # File : app.py # Time : 2025/5/27 15:49 # Author : 紫青宝剑 """ import uvicorn from fastapi import FastAPI, Request, Form, HTTPException from fastapi.params import Depends from pydantic import BaseModel from watchfiles import awatchapp = FastAPI(title="测试小Demo",description="文档描述",version="1.0", )class Item(BaseModel):name: strdescription: str = Noneprice: floattax: float = Nonedef val_item(item: Item):print("接收到了执行的逻辑....")if item.tax < 0.0:raise HTTPException(status_code=400, detail="Price must be greater than zero")else:return item@app.post("/items/", response_model=Item) async def create_item(item: Item = Depends(val_item)):return itemif __name__ == '__main__':uvicorn.run(app, host="127.0.0.1", port=8000)
此时,会直接在模型校验数据的类型之后执行视图函数之前,执行的校验步骤。
-
参数查询
from fastapi import FastAPI, Depends, Query from pydantic import BaseModelapp = FastAPI()class QueryParameters(BaseModel):q: str = Query(..., min_length=3, max_length=50)@app.get("/items/") async def read_items(query_params: QueryParameters = Depends()):return {"q": query_params.q}
QueryParameters
是一个 Pydantic 模型,它定义了一个查询参数q
。通过将query_params
作为依赖项,FastAPI 会自动解析查询参数并将其转换为QueryParameters
实例。 -
前置校验
在路由函数中使用
Depends
,创建一个前置依赖函数来执行复杂的验证逻辑。from fastapi import FastAPI, Depends, HTTPExceptionapp = FastAPI()def complex_query_validator(query: str):if "forbidden" in query:raise HTTPException(status_code=400, detail="Forbidden query")return query@app.get("/items/") async def read_items(query: str = Depends(complex_query_validator)):return {"query": query}
complex_query_validator
是一个依赖函数,它接收一个查询参数query
并对其进行校验。如果校验失败,它会抛出一个HTTPException
。 -
用户认证
Depends
也可以用于用户认证和授权。你可以定义一个依赖函数来验证用户身份,并返回用户信息。然后在路由函数中使用这个依赖函数。from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import HTTPBasic, HTTPBasicCredentials from pydantic import BaseModelapp = FastAPI() security = HTTPBasic()class User(BaseModel):""" 定义用户模型的类。"""username: strpassword: strdef get_current_user(credentials: HTTPBasicCredentials = Depends(security)) -> User:""" 设置校验的函数;"""valid_users = {"Alice": "alice_passwd"}if credentials.username not in valid_users or valid_users[credentials.username] != credentials.password:raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)return User(username=credentials.username, password=credentials.password)@app.post("/users/") async def read_users(user: User = Depends(get_current_user)):return user
在这个例子中,
get_current_user
是一个依赖函数,它接收 HTTP 基本认证的凭据,并验证用户身份。如果验证成功,它会返回一个User
实例。 -
总结
Pydantic
和Depends
的结合使用可以让你在 FastAPI 中实现强大的参数校验和依赖注入功能。你可以通过定义 Pydantic 模型来校验请求数据,同时使用 Depends 来声明依赖项,从而实现复杂的业务逻辑和数据校验。这种组合不仅提高了代码的可维护性和可读性,还增强了 API 的安全性。
继续努力,终成大器!
相关文章:

Pydantic 学习与使用
Pydantic 学习与使用 在 Fastapi 的 Web 开发中的数据验证通常都是在使用 Pydantic 来进行数据的校验,本文将对 Pydantic 的使用方法做记录与学习。 **简介:**Pydantic 是一个在 Python 中用于数据验证和解析的第三方库,它现在是 Python 使…...

PCB设计教程【入门篇】——电路分析基础-基本元件(二极管三极管场效应管)
前言 本教程基于B站Expert电子实验室的PCB设计教学的整理,为个人学习记录,旨在帮助PCB设计新手入门。所有内容仅作学习交流使用,无任何商业目的。若涉及侵权,请随时联系,将会立即处理、 目录 前言 1.二极管 1.发光…...

能按需拆分 PDF 为多个文档的工具
软件介绍 彩凤 PDF 拆分精灵是一款具备 PDF 拆分功能的软件。 功能特点 PDF 拆分功能较为常见,很多 PDF 软件都具备,例如 DC 软件提取 PDF 较为方便,但它不能从一个 PDF 里提取出多个 PDF。据印象,其他 PDF 软件也似乎没有能从…...

Apifox 5 月产品更新|数据模型支持查看「引用资源」、调试 AI 接口可实时预览 Markdown、性能优化
Apifox 新版本上线啦! 看看本次版本更新主要涵盖的重点内容,有没有你所关注的功能特性: 自动解析 JSON 参数名和参数值调试 AI 接口时,可预览 Markdown 格式的内容性能优化:新增「实验性功能」选项 使用独立进程执行…...

LiveGBS海康、大华、宇视、华为摄像头GB28181国标语音对讲及语音喊话:摄像头设备与服务HTTPS准备
LiveGBS海康、大华、宇视、华为摄像头GB28181国标语音对讲及语音喊话:摄像头设备与服务HTTPS准备 1、背景2、准备工作2.1、服务端必备条件(注意事项)2.2、语音对讲设备准备2.2.1、大华摄像机2.2.2、海康摄像机 3、开启音频并开始对讲4、相关问…...

Sqlalchemy 连mssql坑
连接失败: (pyodbc.OperationalError) (08001, [08001] [Microsoft][ODBC Driver 17 for SQL Server]SSL Provider: [error:0A00014D:SSL routines::legacy sigalg disallowed or unsupported] (-1) (SQLDriverConnect)) (Background on this error at: https://sqlalche.me/e/…...
Prompt Engineering 提示工程介绍与使用/调试技巧
1. 介绍 Prompt Engineering 是一种人工智能(AI)技术,它通过设计和改进 AI 的 prompt 来提高 AI 的表现。Prompt Engineering 的目标是创建高度有效和可控的 AI 系统,使其能够准确、可靠地执行特定任务。 如果你从来没有使用过Pr…...

LLaMaFactory - 支持的模型和模板 常用命令
一、 环境准备 激活LLaMaFactory环境,进入LLaMaFactory目录 cd LLaMA-Factoryconda activate llamafactory 下载模型 #模型下载 from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen2.5-0.5B-Instruct) 二、启动一个 Qwen3-0.6B…...

大模型深度学习之双塔模型
前言 双塔模型(Two-Tower Model)是一种在推荐系统、信息检索和自然语言处理等领域广泛应用的深度学习架构。其核心思想是通过两个独立的神经网络(用户塔和物品塔)分别处理用户和物品的特征,并在共享的语义空间中通过相…...
MySQL 8主从同步实战指南:从原理到高可用架构落地
MySQL 8主从同步实战指南:从原理到高可用架构落地 本文将用3000字深度解析MySQL 8主从复制机制,配合全流程部署指南及电商平台实战案例,助你构建高性能数据库集群 一、主从复制核心原理剖析 1.1 复制架构全景图 #mermaid-svg-vdts3hTIyCtz4byk {font-family:"trebuche…...

瑞数6代jsvmp简单分析(天津电子税x局)
国际惯例 今天帮朋友看一个gov网站的瑞数加密(天津电子税x局) 传送门(登陆入口界面) 瑞数6特征 1.服务器会发两次包,第一次响应状态码为412,第二次响应状态码为200。 2.有三重debugger,其中有…...
缓存架构方案:Caffeine + Redis 双层缓存架构深度解析
在高并发、低延迟的现代互联网系统中,缓存是提升系统性能和稳定性的重要手段。随着业务复杂度的增长,单一缓存方案(如仅使用Redis或仅使用本地缓存)已难以满足高性能与一致性需求。 本文将围绕 Caffeine Redis 的双层缓存架构展…...
AI笔记 - 模型调试 - 调试方式
模型调试方式 基础信息打印模型信息计算参数量和计算量过滤原则profile方法get_model_complexity_info方法FlopCountAnalysis方法 基础信息 # 打印执行的设备数量:device_count:1 print(f"device_count:{torch.cuda.device_count()}")# 打印当前网络执行…...

榕壹云物品回收系统实战案例:基于ThinkPHP+MySQL+UniApp的二手物品回收小程序开发与优化
摘要:本文深入解析了一款基于ThinkPHPMySQLUniApp框架开发的二手物品回收小程序——榕壹云物品回收系统的技术实现与商业价值。通过剖析项目背景、核心技术架构、功能特性及系统优势,为开发者与潜在客户提供全面的参考指南,助力资源循环利用与…...

《软件工程》第 9 章 - 软件详细设计
目录 9.1 详细设计的任务与过程模型 9.2 用例设计 9.2.1 设计用例实现方案 9.2.2 构造设计类图 9.2.3 整合并优化用例实现方案 9.3 子系统设计 9.3.1 确立内部设计元素 9.3.2 导出设计类图 9.4 构件设计 9.5 类设计 9.5.1 精化类间关系 9.5.2 精化属性和操作 9.5.…...

WebVm:无需安装,一款可以在浏览器运行的 Linux 来了
WebVM 是一款可以在浏览器中运行的Linux虚拟机。不是那种HTMLJavaScript模拟的UI,完全通过HTML5/WebAssembly技术实现客户端运行。通过集成CheerpX虚拟化引擎,可直接在浏览器中运行未经修改的Debian系统。 Stars 数13054Forks 数2398 主要特点 完整 Lin…...

王树森推荐系统公开课 排序06:粗排模型
shared bottom 表示神经网络被所有特征共享。精排模型主要开销在神经网络,神经网络很大且很复杂。 每做一次推荐,用户塔只做一次推理。物品塔存放入向量数据库。 后期融合模型常用于召回,前期融合模型常用于精排。 物品塔短时间内比较稳…...
go并发编程| channel入门
channel 介绍 channel 是在 Go 的并发编程中使用的,这个工具的作用之一是 goroutine 之间通信(线程通信指的是多个线程之间通过共享数据或协作机制来协调操作,通常需要借助锁来保证同步)。Go 中推荐使用 channel(不同…...

PH热榜 | 2025-05-29
1. Tapflow 2.0 标语:将你的文档转化为可销售的指导手册、操作手册和工作流程。 介绍:Tapflow 2.0将各类知识(包括人工智能、设计、开发、营销等)转化为有条理且可销售的产品。现在你可以导入文件,让人工智能快速为你…...
详解GPU
详解GPU GPU(图形处理器)就像电脑里的 “图形小能手”,原本主要用来画画(渲染图形),现在还能帮忙干很多杂活(并行计算) 一、先认识 GPU 的 “钥匙”:驱动和开发工具 装驱…...
WPF【11_10】WPF实战-重构与美化(配置Material UI框架)
11-16 【UI美化】配置Material UI框架 三种比较主流的 UI 设计规范,分别是: 苹果的扁平化 UI 设计、安卓或者说谷歌 的 Material Design 以及微软的 Metro 风格。 这三种风格都极具特色,不过我们接下来将会使用的是 Material Design 。在 W…...
(自用)Java学习-5.16(取消收藏,批量操作,修改密码,用户更新,上传头像)
1. 取消收藏功能 前端实现: 用户点击“取消收藏”按钮时,前端通过变量status判断当前状态(0为未收藏,1为已收藏)。 发送AJAX请求到后端接口: 添加收藏:/favoriteise/addFavoriteise?pid商品ID…...

【Node.js】部署与运维
个人主页:Guiat 归属专栏:node.js 文章目录 1. Node.js 部署概述1.1 部署的核心要素1.2 Node.js 部署架构全景 2. 传统服务器部署2.1 Linux 服务器环境准备系统更新与基础软件安装创建应用用户 2.2 应用部署脚本2.3 环境变量管理2.4 Nginx 反向代理配置2…...

【Java Web】速通JavaScript
参考笔记:JavaWeb 速通JavaScript_javascript 速通-CSDN博客 目录 一、JavaScript快速入门 1. 基本介绍 2. JavaScript特点 3. JavaScript的引入方式(重要) 3.1 写在script标签中 3.2 以外部文件方式引入 二、JS的数据类型 1. 变量 2. 常用数据类型 3.特殊值 三、…...

TDengine 运维——巡检工具(安装前预配置)
背景 TDengine 的安装部署对环境系统有一定的依赖和要求,安装部署前需要进行环境预配置操作,本文档旨在说明安装前预配置工具在安装 TDengine 前对环境的预配置内容和工具的使用方法。 预配置工具使用方法 工具支持通过 help 参数查看支持的语法 Usa…...
C#索引器详解:让对象像数组一样被访问
索引器是C#中一个强大而实用的特性,它允许我们像访问数组一样访问类的成员。本文将全面介绍索引器的概念、语法、实现方式以及实际应用场景。 索引器基础概念 索引器(Indexer)是一组get和set访问器,与属性类似,但有以…...
机器学习课设
🎓 图像处理课程设计任务书 课程名称: 图像处理与模式识别 课设题目: 基于手工特征提取与传统机器学习方法的图像分类系统实现 一、课设目的 本课程设计旨在加深对图像处理与分类算法的理解,提升图像特征提取、传统机器学习模…...
vue 如何对 div 标签 设置assets内本地背景图片
在 Vue 中为 <div> 设置 assets 目录下的本地背景图片,需要通过 Webpack 或 Vite 等构建工具 处理路径引用。以下是详细实现方法: 一、项目结构说明 假设你的项目结构如下: src/assets/images/bg.jpg # 背景图片components/…...
wsl2 docker重启后没了
参考这篇文章:wsl2 docker重启后没了_mob64ca12f55920的技术博客_51CTO博客...
ubuntu 22.04 配置静态IP、网关、DNS
1、打开配置文件 vi /etc/netplan/00-installer-config.yaml 2、修改文件内容 # This is the network config written by subiquity network:ethernets:ens33:dhcp4: false # 禁用 dhcpaddresses:- 192.168.12.15/24 # 静态IProutes:- to: defaultvia: 192.168.12.254 …...