如何让继承自UUID的自定义类型适配Pydantic模型
问题
我们代码库中有一个继承自uuid.UUID的自定义ID类:
import uuid from typing import Any class ID(uuid.UUID): def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs)
直接将其作为Pydantic模型字段(如class Model(BaseModel): id: ID)时,会触发PydanticSchemaGenerationError。由于Pydantic不支持多继承,无法让ID类同时继承BaseModel和uuid.UUID;手动实现__get_pydantic_json_schema__和__get_pydantic_core_schema__方法后仍出现错误,求正确配置方式。
正确配置方式
无需手动实现复杂的Pydantic schema方法,以下两种方案可可靠解决问题:
方案一:使用Annotated+BeforeValidator
通过验证器将输入转换为自定义ID类型,同时复用Pydantic内置的UUID校验逻辑:
import uuid from typing import Any, Annotated from pydantic import BaseModel, BeforeValidator class ID(uuid.UUID): def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # 定义验证器,处理各种输入类型并转为ID实例 def validate_id(v: Any) -> ID: if isinstance(v, ID): return v # 对字符串、字节、UUID实例等输入,统一转为ID return ID(v) # 用Annotated包装ID类型,绑定验证器 AnnotatedID = Annotated[ID, BeforeValidator(validate_id)] # 定义Pydantic模型 class Model(BaseModel): id: AnnotatedID # 测试示例 if __name__ == "__main__": # 支持字符串格式的UUID m1 = Model(id="12345678-1234-5678-1234-567812345678") print(type(m1.id)) # <class '__main__.ID'> # 支持原生UUID实例 u = uuid.uuid4() m2 = Model(id=u) print(type(m2.id)) # <class '__main__.ID'> # 支持ID实例 i = ID(uuid.uuid4()) m3 = Model(id=i) print(type(m3.id)) # <class '__main__.ID'>
方案二:全局注册类型适配器
通过TypeAdapter为ID类注册全局处理逻辑,后续模型可直接使用ID类型:
import uuid from typing import Any from pydantic import BaseModel, TypeAdapter from pydantic_core import core_schema class ID(uuid.UUID): def __init__(self, *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # 定义ID类的核心校验schema,复用UUID的校验规则 def id_core_schema() -> core_schema.CoreSchema: return core_schema.no_info_wrap_validator_function( lambda v: ID(v) if not isinstance(v, ID) else v, core_schema.uuid_schema(), ) # 注册类型适配器,让Pydantic识别ID类型 TypeAdapter(ID).validate_python = id_core_schema # 直接使用ID类型定义模型 class Model(BaseModel): id: ID # 测试示例 if __name__ == "__main__": m = Model(id="12345678-1234-5678-1234-567812345678") print(type(m.id)) # <class '__main__.ID'>
注意事项
- 两种方案均复用Pydantic内置的UUID校验逻辑,避免重复实现校验规则
- 方案一适合局部场景使用,方案二适合全局统一处理自定义ID类型
- 尽量避免手动实现
__get_pydantic_json_schema__和__get_pydantic_core_schema__,这类内部API易随Pydantic版本变动导致兼容问题
内容的提问来源于stack exchange,提问作者Antonio Gamiz Delgado
相关产品推荐
相关产品推荐

