首页 > Python基础教程 >
-
FastAPI中实现动态条件必填字段的实践
-
Pydantic 基础回顾
在 FastAPI 框架中,Pydantic
模型通过类型注解和字段校验器(validators)实现数据验证。当我们需要实现根据某个字段的值动态决定其他字段是否必填
时,需要组合使用以下特性:
Field 依赖声明:使用 Field() 的 depends 参数
多字段校验器:@model_validator(mode='before') 装饰器
条件验证逻辑:基于 Python 的条件判断表达式
2. 动态必填字段应用场景
假设我们需要开发一个用户注册接口,根据不同的注册类型(邮箱/手机号)动态调整必填字段:
当 register_type=email 时,email 字段必填
当 register_type=mobile 时,mobile 字段必填
当 accept_promotion=True 时,必须填写至少一种联系方式
3. 最佳实践实现方案
PYTHON
from pydantic import BaseModel, Field, model_validator
from typing import Optional, Literal
class UserRegistration(BaseModel):
register_type: Literal["email", "mobile"] # 限定注册类型枚举值
email: Optional[str] = Field(None, pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")
mobile: Optional[str] = Field(None, pattern=r"^1[3-9]\d{9}$")
accept_promotion: bool = False
@model_validator(mode='before')
def validate_required_fields(cls, values):
reg_type = values.get('register_type')
errors = []
# 根据注册类型检查对应字段
if reg_type == "email" and not values.get("email"):
errors.append("email is required for email registration")
elif reg_type == "mobile" and not values.get("mobile"):
errors.append("mobile is required for mobile registration")
# 检查促销订阅条件
if values.get("accept_promotion"):
if not values.get("email") and not values.get("mobile"):
errors.append("email or mobile required for promotion subscription")
if errors:
raise ValueError("; ".join(errors))
return values
- 代码解析
PYTHON
# 字段定义部分
register_type: Literal["email", "mobile"] → 限制输入值只能是枚举值
Field(None, pattern=r"正则表达式") → 设置默认值并添加格式验证
# 验证器核心逻辑
@model_validator(mode='before')
→ 在类型转换前执行验证
values.get('register_type') → 获取字段原始值(未经过类型转换)
values.get("email") → 获取字段原始输入值
raise ValueError → 触发验证错误(FastAPI会自动转换为422响应)
- 完整接口实现
PYTHON
from fastapi import FastAPI
app = FastAPI()
@app.post("/register")
async def user_registration(data: UserRegistration):
# 成功通过验证后才会执行到这里
return {
"message": "Registration successful",
"data": data.model_dump()
}
-
测试用例说明
PYTHON
# 有效请求1(邮箱注册)
{
"register_type": "email",
"email": "user@example.com"
}
# 有效请求2(手机注册+促销订阅)
{
"register_type": "mobile",
"mobile": "13800138000",
"accept_promotion": true
}
# 无效请求1(缺少邮箱)
{
"register_type": "email"
} → 返回422错误:"email is required for email registration"
# 无效请求2(促销订阅但无联系方式)
{
"register_type": "email",
"accept_promotion": true
} → 返回422错误:"email or mobile required for promotion subscription"
-
常见报错解决方案
报错信息:422 Validation Error
JSON
{
"detail": [
{
"type": "value_error",
"msg": "Value error, email is required for email registration",
"loc": [
"body"
]
}
]
}
解决方案:
检查请求体是否满足所有必填条件
验证字段格式是否符合正则表达式要求
使用 print(data.model_dump_json()) 输出模型结构进行调试
在 Swagger 文档页面测试接口时,注意查看自动生成的请求示例
预防建议:
为每个字段添加明确的 description 参数
使用 examples 参数提供典型请求示例
PYTHON
Field(..., description="用户邮箱地址", examples=["user@example.com"])
课后Quiz
Q1:当需要根据两个字段的组合值进行验证时,应该使用哪种验证器?
A) @field_validator
B) @model_validator(mode=’before’)
C) 直接在路由函数中验证
D) 使用多个@field_validator
答案解析
Q2:如何确保手机号字段在特定条件下同时满足格式要求和必填要求?
A) 分别编写格式验证和必填验证
B) 在Field中同时指定pattern和validation函数
C) 使用多个验证器装饰器
D) 以上都是
答案解析
Q3:当收到422错误但不确定具体验证规则时,最佳调试方式是什么?
A) 查看FastAPI自动生成的API文档
B) 在验证器中添加print语句
C) 使用try-except捕获ValidationError
D) 以上都是
答案解析
正确答案:D 组合调试方案: 1. 查阅Swagger文档中的请求示例格式 2. 在验证器中打印values值观察处理过程 3. 通过如下代码捕获详细错误信息:
PYTHON
from pydantic import ValidationError
try:
UserRegistration(**data)
except ValidationError as e:
print(e.errors())
来源:https://blog.cmdragon.cn/posts/1b01bf90607f/