fastapi 默认不支持 mongodb 的 decimal128 类型,需手动注册 pydantic 自定义转换器或封装 decimal128field,并在响应前用 json_util.dumps() 或 str() 显式转换,否则序列化失败或精度丢失。

FastAPI 默认不识别 MongoDB 的 Decimal128 类型,直接返回会触发 Pydantic 序列化失败或静默转成 float,精度立刻丢失——这不是 FastAPI 的 bug,而是类型桥接缺失导致的必然结果。
Pydantic 模型里怎么声明 Decimal128 字段?
Pydantic V2 不原生支持 Decimal128,必须手动注册自定义类型转换器,否则字段会被跳过或报错 ValidationError: unexpected type。
- 不能直接写
price: Decimal128(Pydantic 不认识这个类) - 也不能用
price: Decimal代替——Decimal是 Python 标准库类型,和 MongoDB 的Decimal128二进制格式不兼容,序列化时会丢位数 - 正确做法是:用
price: Annotated[Decimal, Field(..., json_schema_extra={"format": "decimal128"})]声明语义,并在模型model_config中注册解码逻辑 - 更稳妥的方案是封装一个自定义字段类型,例如
Decimal128Field,内部用@field_validator拦截输入,对Decimal128实例原样透传,对字符串/数字则调用Decimal128.fromString()或抛错
从 MongoDB 查询后怎么避免序列化崩溃?
即使数据库存的是合法 Decimal128,FastAPI 默认 JSON 响应器无法序列化它,会抛出 TypeError: Object of type Decimal128 is not JSON serializable。
- 必须在响应前做一次类型归一:用
json_util.dumps()(来自pymongo)或手动遍历文档,把所有Decimal128转成字符串(如str(d128))再交给 Pydantic - 别依赖
response_model自动处理——它只认 Python 内置类型或已注册的 Pydantic 类型,不会调用pymongo的编码器 - 如果用 SQLModel 或 ORM 抽象层,注意它们完全不支持
Decimal128,必须绕过 ORM 直接操作AsyncIOMotorCollection - 聚合管道中若用了
$sum等算子,务必确认所有输入字段都是纯Decimal128;混入int或double会导致结果降级为float,此时再转字符串也晚了
前端传来的金额字符串怎么安全转成 Decimal128 插入?
用户提交的 "199.99" 必须严格走字符串路径初始化,任何中间经过 JS 数值运算都会失真。
- FastAPI 路径参数或请求体中接收时,先用
str类型接收,再在校验阶段调用Decimal128.fromString(value)——不能用Decimal128(value),后者接受数字字面量,已丢失精度 - 如果字段允许为空或含非法格式(如
"N/A"),Decimal128.fromString()会直接抛异常中断整个请求;必须前置用@field_validator+try/except包裹,并返回None或抛ValueError让 FastAPI 统一转成 422 - 插入前建议加一层
$match: { $expr: { $isNumber: "$amount" } }查询校验,排除历史遗留的非数值数据干扰聚合逻辑
最易被忽略的一点:MongoDB 驱动返回的文档是 dict,但其中的 Decimal128 实例在 FastAPI 生命周期里没有任何自动转换钩子;你得在每个涉及金额的接口里显式处理它,而不是指望某处“全局配置”能一劳永逸。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











