如何构建序列化时不产生嵌套结构的Pydantic模型?
如何构建序列化时不产生嵌套结构的Pydantic模型?
嘿,这个需求我之前也碰到过!既要让Foo模型保留数据验证能力,又不想在序列化Bar时出现嵌套结构,直接输出原始的字符串值对吧?用Pydantic自带的工具就能轻松实现,给你两个完全匹配你需求的方案:
方案一:轻量自定义类型(适合简单验证场景)
如果你的Foo只需要做基础的字符串验证,不需要复杂的模型结构,用Annotated结合验证器和序列化器是最简洁的方式:
from pydantic import BaseModel, field_validator, PlainSerializer, WithJsonSchema from typing import Annotated # 定义带验证的自定义类型Foo,直接基于字符串扩展 Foo = Annotated[ str, # 这里写你的验证逻辑,比如检查字符串长度至少3位 field_validator(lambda v: len(v) >= 3 or ValueError("字符串长度不能少于3位")), # 指定序列化时直接输出原始字符串,避免嵌套 PlainSerializer(lambda x: x, return_type=str), WithJsonSchema({"type": "string"}) ] class Bar(BaseModel): bar: Foo # 完全符合你的测试用例 y = Bar(bar="xxx") # 这里甚至可以直接传字符串,Pydantic会自动转成Foo类型 print(y.json()) # 输出: {"bar": "xxx"} # 验证功能正常触发,传入不符合要求的值会报错 try: Bar(bar="xx") except Exception as e: print(e) # 抛出"字符串长度不能少于3位"的验证错误
方案二:基于BaseModel的Foo(适合复杂验证/结构场景)
如果你需要Foo是一个正经的BaseModel子类,或者有更复杂的验证逻辑,那可以用__root__字段支持直接传字符串实例化,再给Bar的字段加个序列化器:
from pydantic import BaseModel, field_validator, field_serializer class Foo(BaseModel): __root__: str # 用__root__字段,支持直接用Foo('xxx')实例化 # 自定义验证逻辑,比如检查字符串必须包含字母 @field_validator("__root__") def check_has_letter(cls, v): if not any(c.isalpha() for c in v): raise ValueError("字符串必须包含至少一个字母") return v class Bar(BaseModel): bar: Foo # 序列化时直接取出Foo的核心值,避免嵌套 @field_serializer("bar") def serialize_bar(self, foo_instance: Foo) -> str: return foo_instance.__root__ # 完美匹配你的测试代码 y = Bar(bar=Foo('xxx')) print(y.json()) # 输出: {"bar": "xxx"} # 验证逻辑正常工作 try: Bar(bar=Foo('123')) except Exception as e: print(e) # 抛出"字符串必须包含至少一个字母"的错误
这两个方案都能满足你的要求:Foo负责数据验证,序列化Bar时直接输出原始字符串,完全没有嵌套结构。你可以根据自己的实际需求选,简单验证用方案一,复杂场景用方案二就行~
备注:内容来源于stack exchange,提问作者nipil
相关产品推荐
相关产品推荐

