使用Pydantic为FastAPI查询参数自定义验证引发内部服务器错误
解决FastAPI查询参数自定义验证导致内部服务器错误的问题
问题描述
需要为GET端点的查询参数n添加以下验证规则:
- 为0到10之间的整数
- 必须是偶数
使用Query(gt=0, lt=10)可实现第一个规则,但添加自定义偶数验证后,触发验证失败时应用出现内部服务器错误(500)。
原错误代码:
from fastapi import FastAPI, Depends, Query from pydantic import BaseModel, ValidationError, validator app = FastAPI() class CommonParams(BaseModel): n: int = Query(default=..., gt=0, lt=10) @validator('n') def validate(cls, v): if v%2 != 0: raise ValueError("Number is not even :( ") return v @app.get("/") async def root(common: CommonParams = Depends()): return {"n": common.n}
问题原因
核心错误是在Pydantic BaseModel的字段中错误使用了FastAPI的Query对象。Query是FastAPI用于声明路径操作函数查询参数的工具,而BaseModel的字段验证应该使用Pydantic的Field。这种混用导致Pydantic验证器抛出的异常无法被FastAPI正确捕获,进而触发500内部错误。
解决方案
方案1:修正BaseModel字段定义(推荐多参数复用场景)
将BaseModel中的Query替换为Pydantic的Field,FastAPI会自动处理Pydantic验证器抛出的异常,返回标准422验证错误:
from fastapi import FastAPI, Depends from pydantic import BaseModel, Field, validator app = FastAPI() class CommonParams(BaseModel): n: int = Field(..., gt=0, lt=10) @validator('n') def must_be_even(cls, v): if v % 2 != 0: raise ValueError("Number must be even") return v @app.get("/") async def root(common: CommonParams = Depends()): return {"n": common.n}
方案2:直接在路径操作中定义验证(适合简单场景)
无需BaseModel,直接在查询参数中添加验证逻辑,抛出FastAPI的HTTPException返回标准422错误:
from fastapi import FastAPI, Query, HTTPException app = FastAPI() @app.get("/") async def root(n: int = Query(..., gt=0, lt=10)): if n % 2 != 0: raise HTTPException(status_code=422, detail="Number must be even") return {"n": n}
方案3:使用Annotated+PlainValidator(FastAPI 0.95+)
通过Annotated组合Query规则和自定义验证器,代码更模块化:
from fastapi import FastAPI, Query, HTTPException from typing import Annotated from pydantic import PlainValidator app = FastAPI() def validate_even(v: int) -> int: if v % 2 != 0: raise HTTPException(status_code=422, detail="Number must be even") return v @app.get("/") async def root( n: Annotated[int, Query(gt=0, lt=10), PlainValidator(validate_even)] ): return {"n": n}
效果验证
使用修正后的代码,当请求localhost:8000?n=1时,会返回422状态码及标准错误响应:
{ "detail": [ { "loc": ["query", "n"], "msg": "Number must be even", "type": "value_error" } ] }
内容的提问来源于stack exchange,提问作者ooo
相关产品推荐
相关产品推荐

