在 FastAPI 中自定义 Pydantic 的校验错误消息

引言

FastAPI 是一个基于 Python 的高性能 Web 框架,专注于 API 开发,使用 Python 类型注解提供自动数据验证、序列化和高效的异步支持(基于 Starlette 和 Pydantic)。Pydantic 是一个数据验证和设置管理库,主要用于解析 JSON、校验数据类型。

Pydantic 添加校验条件是比较简单和自然的,然而如果要自定义错误消息则显得有些繁琐,下面来简单讨论一下。

依赖包说明

在开始讨论之前,先提一下执行本文代码所依赖的包。为方便计,安装依赖包使用的是傻瓜式的安装方式。

安装命令如下:

pip install "fastapi[all]"

通过上面的安装命令,会安装许多和 fastapi 相关的依赖包,和本文中直接相关的两个包分别是 fastapi 和 pydantic。其中 fastapi 的版本是 fastapi==0.115.11, pydantic 的版本是 pydantic==2.10.6

本文使用的 Python 版本是 Python 3.9.6

Pydantic 自定义错误消息

Pydantic 为数据添加校验最简单的方式是使用 Field 给模型类的字段添加校验条件,如下所示:

from pydantic import BaseModel, Field  
  
class User(BaseModel):  
    username: str = Field(..., min_length=3)  
    age: int = Field(..., ge=0)

上面的代码看上去和许多库添加数据校验条件的方式差不多,不过这个 Field 有些迷惑性,它实际上是一个工厂函数,不像其他库那样是描述符。Field 工厂函数返回的是 FieldInfo 实例,FieldInfo 实现了类似描述符的功能,能对字段进行校验。

当提供的值通不过 FieldInfo 中定义的校验条件时,Pydantic 会抛出异常并给出错误消息。在上面的代码后面添加以下代码:

try:  
    user = User(username="ab", age=16)  
except ValidationError as e:  
    print(e.json())

运行上面的代码将输出:

[{
   
   "type":"string_too_short","loc":["username"],"msg":"String should have at least 3 characters","input"
<think> 我们讨论的是FastAPI中使用Pydantic v2的BaseModel进行字段验证,特别是用户名和密码的Body字段。 根据引用[1]的内容,我们知道FastAPI的响应模型使用Pydantic模型来定义数据结构,但这里我们需要的是请求体的验证,同样使用Pydantic模型。 在FastAPI中,我们通常使用Pydantic模型来定义请求体的结构,并进行验证和序列化。 对于用户名和密码的验证,我们可以创建一个继承自BaseModel的类,定义用户名和密码字段,并添加相应的验证规则。 注意:用户要求使用Pydantic v2。Pydantic v2引入了许多新特性,但基本用法与v1相似。 以下是步骤: 1. 安装FastAPIPydantic v2(如果尚未安装)。 2. 创建一个Pydantic模型,定义用户名和密码字段,并添加验证规则(如最小长度、最大长度、正则表达式等)。 3. 在FastAPI路径操作函数中,将该模型作为参数(使用Body)。 示例代码: 首先,安装(如果需要): pip install fastapi pip install pydantic>=2.0 然后,创建一个模型,例如`UserAuth`模型: ```python from fastapi import FastAPI, Body from pydantic import BaseModel, Field app = FastAPI() # 定义请求体模型 class UserAuth(BaseModel): username: str = Field(..., min_length=3, max_length=20, pattern=r"^[a-zA-Z0-9_]+$") password: str = Field(..., min_length=8, max_length=32) @app.post("/login") async def login(user: UserAuth): # 这里处理登录逻辑 return {"username": user.username, "message": "Login successful"} ``` 说明: - 我们定义了一个`UserAuth`类,继承自`BaseModel`。 - `username`字段:字符串类型,最小长度3,最大长度20,并且使用正则表达式限制只能包含字母、数字和下划线(根据需求调整)。 - `password`字段:字符串类型,最小长度8,最大长度32。 - 在路径操作函数`login`中,我们将`user`参数的类型指定为`UserAuth`,这样FastAPI会自动验证请求体是否符合该模型。 如果请求体不符合要求(例如用户名长度不足3或密码长度不足8),FastAPI会自动返回422 Unprocessable Entity错误,并包含详细的错误信息。 另外,关于密码的安全处理: - 在实际应用中,密码通常不会以明文形式存储在数据库中,也不会在响应中返回。这里为了示例,只返回了用户名。 - 我们可能需要对密码进行哈希处理,可以使用如`passlib`库。 如果需要更复杂的验证,可以使用Pydantic的validator(在Pydantic v2中,validator被替换为`@field_validator`等): ```python from pydantic import BaseModel, Field, field_validator class UserAuth(BaseModel): username: str = Field(..., min_length=3, max_length=20, pattern=r"^[a-zA-Z0-9_]+$") password: str = Field(..., min_length=8, max_length=32) @field_validator('password') def password_must_contain_special_chars(cls, v): if not any(char in "!@#$%^&*()_+-=[]{}|;:,.<>?/" for char in v): raise ValueError('password must contain at least one special character') return v ``` 在这个例子中,我们添加了一个验证器,确保密码包含至少一个特殊字符。 注意:验证器的使用在Pydantic v1和v2中有所不同。在v2中,我们使用`@field_validator`装饰器,并指定字段名。 因此,我们可以根据需求定义模型和验证规则。 引用说明:我们参考了FastAPI的响应模型特性,但实际上请求体模型同样基于Pydantic,原理相同[^1]。 </think> 在 FastAPI 中使用 Pydantic v2 的 `BaseModel` 进行用户名和密码字段验证的方法如下,包含关键验证规则和代码实现: ### 1. **创建 Pydantic 验证模型** ```python from pydantic import BaseModel, Field, field_validator class UserLogin(BaseModel): username: str = Field( ..., min_length=3, max_length=20, pattern=r"^[a-zA-Z0-9_]+$", # 只允许字母、数字和下划线 examples=["john_doe123"], # OpenAPI 文档示例 description="用户名需3-20字符" ) password: str = Field( ..., min_length=8, max_length=32, examples=["SecureP@ssw0rd"], description="密码需8-32字符" ) # 自定义密码强度验证器 @field_validator('password') def validate_password_strength(cls, v): if not any(char.isdigit() for char in v): raise ValueError("密码需包含数字") if not any(char.isupper() for char in v): raise ValueError("密码需包含大写字母") if not any(char in "!@#$%^&*" for char in v): raise ValueError("密码需包含特殊字符 !@#$%^&*") return v ``` ### 2. **在 FastAPI 路由中使用** ```python from fastapi import FastAPI, Body, HTTPException app = FastAPI() @app.post("/login") async def login(user: UserLogin = Body(...)): # 验证通过后执行业务逻辑 return {"message": f"用户 {user.username} 登录成功"} ``` ### 关键验证功能说明: 1. **用户名验证** - 长度限制:`min_length=3`, `max_length=20` - 格式限制:正则表达式 `^[a-zA-Z0-9_]+$` 禁止特殊符号 - OpenAPI 集成:自动生成带示例的文档 2. **密码验证** - 基础规则:长度 8-32 字符 - 自定义验证器: - 必须包含数字和大写字母 - 必须包含至少一个特殊字符 `!@#$%^&*` - 自动返回具体错误信息(如"密码需包含数字") 3. **错误处理** - 无效数据自动返回 422 错误,包含详细错误原因: ```json { "detail": [ { "loc": ["body", "password"], "msg": "密码需包含大写字母", "type": "value_error" } ] } ``` ### 3. 安全增强建议 1. **密码哈希处理**(实际存储前必须添加): ```python from passlib.context import CryptContext pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # 在接收密码后立即哈希 hashed_password = pwd_context.hash(user.password) ``` 2. **敏感字段屏蔽**: ```python class UserLogin(BaseModel): password: str = Field(..., exclude=True) # 从日志和响应中排除 ``` 此实现确保了对用户名和密码的严格验证,同时通过 Pydantic v2 的特性与 FastAPI 深度集成,自动生成 API 文档并返回明确验证错误信息[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值