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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 11:13:14