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

基于JSON配置动态生成FastAPI的Pydantic模型遇问题求助

动态生成Pydantic模型在FastAPI中不显示及验证错误的解决方案

需求与问题背景

我希望通过JSON配置设置API端点的请求参数,示例JSON配置如下:

{
   "first_name": "string",
   "last_name": "string",
   "age": "integer"
}

我尝试用以下代码动态生成Pydantic模型类:

from pydantic import BaseModel, validator

class Record(BaseModel):
    pass

def generate_pydantic_record_model(config):
    for attribute_name, data_type in config['attributes'].items():

        if data_type == "string":
            setattr(Record, attribute_name, str)

        elif data_type == "date":
            setattr(Record, attribute_name, str)

            @validator(attribute_name, allow_reuse=True)
            def validate_date_format(cls, value, values, attribute_name=attribute_name, config=config):
                date_format = config['attributes'][attribute_name].get(
                    "format", "%d/%m/%y")
                if value is not None:
                    try:
                        datetime.strptime(value, date_format)
                    except ValueError:
                        raise ValueError(
                            f"Invalid date format for '{attribute_name}'. Date should be in the format {date_format}")
                return value

        elif data_type == "integer":
            setattr(Record, attribute_name, int)

generate_pydantic_record_model(validator_converter.data_config)

目前遇到两个问题:

  • 生成的Record类未在FastAPI的Swagger UI中显示
  • 运行时出现验证错误

问题原因及修复方案

1. Swagger UI不显示模型的核心原因

FastAPI依赖Pydantic模型的字段元数据生成OpenAPI文档(即Swagger UI)。直接用setattr给已定义的BaseModel子类添加字段,无法正确注册字段的元信息,导致FastAPI无法识别这些动态字段,自然不会在Swagger中展示。

正确做法是用pydantic.create_model动态生成新的模型类,而非修改已存在的Record类,该方法会自动处理字段元数据的注册。

2. 验证错误的具体原因

  • 代码缺失datetime导入,调用datetime.strptime会抛出NameError
  • 直接给已有模型动态添加验证器,不符合Pydantic的模型初始化机制,验证器无法正确绑定
  • 配置结构不兼容:示例配置中字段值是字符串类型(如"string"),但代码中尝试调用.get("format"),会触发AttributeError

修复后的完整代码

from pydantic import BaseModel, validator, create_model
from datetime import datetime

def generate_pydantic_record_model(config):
    fields = {}
    validators = {}

    for attribute_name, field_config in config.items():
        # 兼容两种配置格式:字符串类型转为统一字典格式
        if isinstance(field_config, str):
            field_config = {"type": field_config}
        
        data_type = field_config["type"]
        if data_type == "string":
            fields[attribute_name] = (str, ...)  # ...表示必填,可选字段用None替代
        elif data_type == "date":
            fields[attribute_name] = (str, ...)
            date_format = field_config.get("format", "%d/%m/%y")
            
            # 定义绑定当前字段信息的验证器
            def validate_date(cls, value, attr_name=attribute_name, fmt=date_format):
                if value is not None:
                    try:
                        datetime.strptime(value, fmt)
                    except ValueError:
                        raise ValueError(f"Invalid date format for '{attr_name}'. Expected: {fmt}")
                return value
            
            validators[f"validate_{attribute_name}_date"] = validator(attribute_name, allow_reuse=True)(validate_date)
        elif data_type == "integer":
            fields[attribute_name] = (int, ...)
    
    # 动态生成新的Pydantic模型
    Record = create_model("Record", **fields, __validators__=validators)
    return Record

# 示例配置(支持date类型的格式配置)
sample_config = {
    "first_name": "string",
    "last_name": "string",
    "age": "integer",
    "birth_date": {"type": "date", "format": "%Y-%m-%d"}
}

# 生成模型
Record = generate_pydantic_record_model(sample_config)

FastAPI中使用示例

from fastapi import FastAPI

app = FastAPI()

@app.post("/records/")
async def create_record(record: Record):
    return record.dict()

内容的提问来源于stack exchange,提问作者Karki Bois

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:53:15