在FastAPI接口开发中,前端传递的参数常以字符串形式传输,当接口需要布尔类型参数时,默认的Pydantic校验仅支持true、false、1、0等有限格式,无法直接兼容yes、no、on、off等常见字符串表示。我们可以通过多种方式实现更灵活的字符串到布尔值转换。

方案一:使用BeforeValidator自定义转换逻辑
Pydantic V2版本提供了BeforeValidator,可以在数据校验前对输入值进行预处理,非常适合做字符串到布尔值的转换。我们可以定义一个通用的转换函数,覆盖多种字符串格式。
from pydantic import BaseModel, BeforeValidator
from typing import Annotated
# 定义字符串转布尔值的转换函数
def str_to_bool(v):
if isinstance(v, bool):
return v
if isinstance(v, str):
# 统一转为小写后判断
lower_v = v.lower()
if lower_v in ("true", "yes", "y", "1", "on"):
return True
if lower_v in ("false", "no", "n", "0", "off"):
return False
# 其他情况抛出校验错误
raise ValueError(f"无法将值 {v} 转换为布尔类型")
# 定义带转换逻辑的布尔类型注解
BoolFromStr = Annotated[bool, BeforeValidator(str_to_bool)]
class UserConfig(BaseModel):
# 使用该注解类型的字段会自动触发转换
is_active: BoolFromStr
is_admin: BoolFromStr
# 测试示例
config = UserConfig(is_active="yes", is_admin="0")
print(config.is_active) # 输出 True
print(config.is_admin) # 输出 False
方案二:自定义Pydantic类型
如果需要复用的转换逻辑较多,也可以自定义一个Pydantic类型,封装转换逻辑,使用起来更简洁。
from pydantic import GetCoreSchemaHandler
from pydantic_core import core_schema
from typing import Any
class FlexibleBool:
"""支持多种字符串格式的布尔类型"""
def __init__(self, value: bool):
self.value = value
@classmethod
def __get_pydantic_core_schema__(
cls,
_source_type: Any,
_handler: GetCoreSchemaHandler,
) -> core_schema.CoreSchema:
def validate(v: Any) -> bool:
if isinstance(v, bool):
return v
if isinstance(v, str):
lower_v = v.lower()
if lower_v in ("true", "yes", "y", "1", "on"):
return True
if lower_v in ("false", "no", "n", "0", "off"):
return False
raise ValueError(f"无法将值 {v} 转换为布尔类型")
return core_schema.with_info_plain_schema(
core_schema.no_info_plain_serializer(
core_schema.plain_validator_function(validate)
)
)
class TaskParams(BaseModel):
enable_log: FlexibleBool
auto_retry: FlexibleBool
# 测试示例
params = TaskParams(enable_log="on", auto_retry="n")
print(params.enable_log) # 输出 True
print(params.auto_retry) # 输出 False
方案三:在FastAPI接口中单独处理参数
如果仅个别接口需要特殊处理,也可以在接口函数内单独做转换,不需要修改全局的Pydantic配置。
from fastapi import FastAPI, Query
from typing import Optional
app = FastAPI()
def parse_str_bool(s: Optional[str]) -> Optional[bool]:
if s is None:
return None
lower_s = s.lower()
if lower_s in ("true", "yes", "y", "1", "on"):
return True
if lower_s in ("false", "no", "n", "0", "off"):
return False
raise ValueError(f"无效的布尔字符串: {s}")
@app.get("/items")
def get_items(
is_available: str = Query(None, description="是否可用,支持true/false/yes/no/1/0等格式")
):
# 手动转换参数
bool_flag = parse_str_bool(is_available)
return {"is_available": bool_flag}
不同方案的选择建议
如果项目中多处需要字符串转布尔值的逻辑,优先选择BeforeValidator或者自定义类型,可以统一逻辑减少重复代码。如果仅个别接口有特殊需求,在接口内单独处理更灵活,不会影响其他接口的默认行为。转换函数可以根据业务需求扩展支持的字符串格式,比如增加中文的"是"、"否"等取值,适配更多场景。
| 方案 | 适用场景 | 优点 |
|---|---|---|
| BeforeValidator | 多处复用转换逻辑 | 逻辑集中,符合Pydantic V2规范,易维护 |
| 自定义类型 | 复杂转换逻辑复用 | 封装性好,使用简洁,可扩展性强 |
| 接口内单独处理 | 个别接口特殊需求 | 灵活度高,不影响全局配置 |