PostgreSQL JSON字段中区分联合类型的Pydantic验证问题
问题描述
PostgreSQL表中存在一个JSON字段form_config,存储表单字段结构,内容如下:
[ { "label": "Age", "type": "number", "required": true, "min": 0, "max": null }, { "label": "Name", "type": "text", "required": true, "minLength": 0, "maxLength": null }, { "label": "City", "type": "autocomplete", "required": true, "api": { "url": "api/countries", "method": "GET", "labelKey": "name" } } ]
通过FastAPI编写的API会获取该数据,并基于如下响应Schema返回结果:
class FormConfigResponse(BaseModel): config : List[FormFieldModel]
其中表单字段的Schema通过鉴别器定义:
from enum import Enum from typing import List, Union, Literal, Annotated from pydantic import BaseModel, Field class FormFieldType(str, Enum): text = 'text' number = 'number' autocomplete= 'autocomplete' class FormFieldBase(BaseModel): label: str type: FormFieldType required: bool = True class TextField(FormFieldBase): type: Literal[FormFieldType.text] = FormFieldType.text minLength: int|None maxLength: int|None class NumberField(FormFieldBase): type: Literal[FormFieldType.number] = FormFieldType.number min: int|None max: int|None class APIAutoCompleteConfig(BaseModel): url: str method: str labelKey: str class AutoCompleteField(FormFieldBase): type: Literal[FormFieldType.autocomplete] = FormFieldType.autocomplete api: APIAutoCompleteConfig # 带鉴别器的联合类型 FormFieldModel = Annotated[Union[NumberField, TextField, AutoCompleteField], Field(discriminator='type')]
在API处理代码中按如下方式返回数据时:
return FormConfigResponse( config = form_config )
出现以下错误:
fastapi_app | content = await serialize_response( fastapi_app | File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 155, in serialize_response fastapi_app | raise ResponseValidationError( fastapi_app | fastapi.exceptions.ResponseValidationError: 1 validation errors: fastapi_app | {'type': 'model_attributes_type', 'loc': ('response', 'config'), 'msg': 'Input should be a valid dictionary or object to extract fields from', 'input': [NumberField(label='Age', type=<FormFieldType.number: 'number'>, required=True, min=0, max=None), TextField(label='Name', type=<FormFieldType.text: 'text'>, required=True, minLength=0, maxLength=None), AutoCompleteField(label='City', type=<FormFieldType.autocomplete: 'autocomplete'>, required=True, api=APIAutoCompleteConfig(url='api/countries', method='GET', labelKey='name'))]}
错误提示为「Input should be a valid dictionary or object to extract fields from」,需要排查问题原因并解决。
问题分析与解决
原因
从数据库取出的form_config已经被自动解析为Pydantic模型实例的列表(比如通过ORM框架自动映射),而FormConfigResponse的config字段定义为List[FormFieldModel],Pydantic期望接收的是可被解析为模型的原始数据(字典或JSON结构),而非已经实例化的模型对象。此时直接传入模型实例列表会触发验证逻辑冲突,导致报错。
解决方法
将模型实例列表转换为字典列表后再传入响应模型,具体修改代码如下:
return FormConfigResponse( config = [item.model_dump() for item in form_config] )
如果从数据库取出的form_config是未被解析的原始字典列表(而非模型实例),则可以直接传入,无需转换:
# 当form_config为字典列表时直接使用 return FormConfigResponse(config=form_config)
核心逻辑是:确保传入FormConfigResponse的config参数是Pydantic可直接解析的原始数据结构,而非已经实例化的模型对象。
内容的提问来源于stack exchange,提问作者Ouroboros
相关产品推荐
相关产品推荐

