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
相关产品推荐
相关产品推荐

