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

