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

SQLModel字段验证器未触发问题求助(FastAPI场景)

问题分析与解决方案

你的核心问题在于:带table=True的SQLModel类同时作为ORM模型和Pydantic数据模型时,字段类型声明与输入类型的冲突导致自定义验证器未被触发。

为什么原代码不生效?

你将data字段声明为str类型,当请求传入dict时,Pydantic的类型检查逻辑会优先于mode="before"的自定义验证器执行。由于dict无法直接转换为str,正常情况下会返回422验证错误,但SQLModel与ORM的绑定逻辑特殊,这个错误未被抛出,反而直接将原始dict赋值给了foo.data,最终导致数据库绑定异常,且你的验证器全程未被调用。

解决方案

方案1:拆分请求体模型与ORM模型

创建独立的请求体模型处理输入验证,再映射到ORM模型,这是更清晰的分层写法:

import typing
import json
import pydantic
import sqlmodel
import fastapi

# 仅用于接收请求的Pydantic模型
class FooCreate(pydantic.BaseModel):
    data: str | dict

    @pydantic.field_validator("data", mode="before")
    def serialize_dict(cls, value):
        if isinstance(value, dict):
            return json.dumps(value)
        return value

# ORM模型,仅用于数据库操作
class Foo(sqlmodel.SQLModel, table=True):
    id: typing.Optional[int] = sqlmodel.Field(primary_key=True)
    data: str

@app.post("/foos")
def create_foo(foo_create: FooCreate, session: sqlmodel.Session = fastapi.Depends(get_session)):
    foo = Foo(**foo_create.model_dump())
    session.add(foo)
    session.commit()
    return fastapi.Response()

方案2:调整ORM模型的字段类型

修改data字段的类型声明,允许接收str或dict,确保自定义验证器能被触发:

import typing
import json
import pydantic
import sqlmodel
import fastapi

class Foo(sqlmodel.SQLModel, table=True):
    id: typing.Optional[int] = sqlmodel.Field(primary_key=True)
    data: typing.Union[str, dict]

    @pydantic.field_validator("data", mode="before")
    def serialize_dict(cls, value):
        if isinstance(value, dict):
            return json.dumps(value)
        return value

@app.post("/foos")
def create_foo(foo: Foo, session: sqlmodel.Session = fastapi.Depends(get_session)):
    session.add(foo)
    session.commit()
    return fastapi.Response()

内容的提问来源于stack exchange,提问作者Daniel Walker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:03:11