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

如何创建Pydantic泛型类型实现长度校验与进制转换?

实现Pydantic泛型校验类型

需求概述

项目中有大量重复的模型校验逻辑(如密码长度、用户名字符校验),希望通过泛型类实现复用,比如定义String[15,32]、SecretBytes[6,100]这类带参数的类型;同时需要处理不同进制的整数,通过Int[16]或Int[10]让Pydantic自动转换值到指定进制。


一、泛型字符串/秘钥字节校验

实现代码

from typing import Any, Callable, TypeVar, Generic
from pydantic_core import core_schema
from typing_extensions import get_args
from pydantic import BaseModel, SecretBytes

# 定义长度约束的类型变量
MinLen = TypeVar('MinLen', bound=int)
MaxLen = TypeVar('MaxLen', bound=int)

class String(str, Generic[MinLen, MaxLen]):
    @classmethod
    def __get_pydantic_core_schema__(
        cls, source: Any, handler: Callable[[Any], core_schema.CoreSchema]
    ) -> core_schema.CoreSchema:
        # 获取泛型参数:最小长度、最大长度
        args = get_args(source)
        min_len, max_len = args if len(args) == 2 else (0, float('inf'))
        
        # 构建基础字符串校验规则,包含长度限制
        str_schema = core_schema.str_schema(
            min_length=min_len,
            max_length=max_len,
            strict=False
        )
        
        # 校验后转换为String实例
        def validate_and_convert(v: str, info) -> String:
            return String(v)
        
        # 组合校验规则:先做长度校验,再转换类型
        schema = core_schema.general_after_validator_function(
            validate_and_convert,
            str_schema
        )
        
        # 支持直接传入String实例
        instance_schema = core_schema.is_instance_schema(cls)
        return core_schema.union_schema([instance_schema, schema])

class SecretBytesGeneric(SecretBytes, Generic[MinLen, MaxLen]):
    @classmethod
    def __get_pydantic_core_schema__(
        cls, source: Any, handler: Callable[[Any], core_schema.CoreSchema]
    ) -> core_schema.CoreSchema:
        args = get_args(source)
        min_len, max_len = args if len(args) == 2 else (0, float('inf'))
        
        # 构建带长度限制的秘钥字节校验规则
        secret_bytes_schema = core_schema.secret_bytes_schema(
            min_length=min_len,
            max_length=max_len,
            strict=False
        )
        
        def validate_and_convert(v: bytes | str, info) -> SecretBytesGeneric:
            return SecretBytesGeneric(v)
        
        schema = core_schema.general_after_validator_function(
            validate_and_convert,
            secret_bytes_schema
        )
        
        instance_schema = core_schema.is_instance_schema(cls)
        return core_schema.union_schema([instance_schema, schema])

# 别名简化使用
SecretBytes = SecretBytesGeneric

测试用例

class User(BaseModel):
    username: String[15, 32]
    password: SecretBytes[6, 100]

# 合法输入
user = User(username="valid_username_12345", password="secure_pass_123")
print(user.username)  # valid_username_12345
print(user.password)  # SecretBytes(b'secure_pass_123')

# 非法输入:用户名长度不足
try:
    User(username="short", password="secure_pass_123")
except Exception as e:
    print(e)
    # 输出:1 validation error for User
    # username
    #   String should have at least 15 characters [type=string_too_short, input_value='short', input_type=str]

二、泛型进制整数转换

实现代码

from typing import Any, Callable, TypeVar, Generic
from pydantic_core import core_schema
from typing_extensions import get_args
from pydantic import BaseModel

# 定义进制的类型变量
Base = TypeVar('Base', bound=int)

class Int(int, Generic[Base]):
    @classmethod
    def __get_pydantic_core_schema__(
        cls, source: Any, handler: Callable[[Any], core_schema.CoreSchema]
    ) -> core_schema.CoreSchema:
        # 获取泛型参数:目标进制
        args = get_args(source)
        base = args[0] if args else 10
        
        # 自定义校验与转换逻辑
        def validate_int_with_base(v: Any, info) -> Int:
            if isinstance(v, str):
                # 按指定进制解析字符串
                try:
                    return Int(int(v, base=base))
                except ValueError:
                    raise ValueError(f"无法将字符串'{v}'解析为{base}进制整数")
            elif isinstance(v, int):
                # 整数直接返回
                return Int(v)
            else:
                raise TypeError(f"输入类型{type(v)}不支持,应为字符串或整数")
        
        # 基础整数校验规则 + 自定义转换
        int_schema = core_schema.int_schema(strict=False)
        schema = core_schema.general_after_validator_function(
            validate_int_with_base,
            int_schema
        )
        
        # 支持直接传入Int实例
        instance_schema = core_schema.is_instance_schema(cls)
        return core_schema.union_schema([instance_schema, schema])

测试用例

class NumberModel(BaseModel):
    hex_num: Int[16]
    dec_num: Int[10]
    oct_num: Int[8]

# 合法输入:字符串按指定进制解析,整数直接接受
model = NumberModel(hex_num="1A", dec_num=26, oct_num="32")
print(model.hex_num)  # 26 (十进制整数)
print(model.dec_num)  # 26
print(model.oct_num)  # 26

# 非法输入:无法解析为指定进制
try:
    NumberModel(hex_num="G", dec_num=26, oct_num="32")
except Exception as e:
    print(e)
    # 输出:1 validation error for NumberModel
    # hex_num
    #   无法将字符串'G'解析为16进制整数 [type=value_error, input_value='G', input_type=str]

关键实现要点

  • 利用Generic和TypeVar定义泛型参数,约束参数类型(如长度必须为整数,进制必须合法)
  • 通过get_args(source)提取泛型参数(如String[15,32]的参数为(15,32))
  • 基于Pydantic核心Schema构建校验规则,结合general_after_validator_function完成类型转换
  • 添加is_instance_schema支持直接传入自定义类型的实例,提升灵活性

内容的提问来源于stack exchange,提问作者Alan Latte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:18:05