You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 19:39:23