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

pydantic.Field搭配自定义数据类型使用时校验不生效问题

问题原因
  • Pydantic v1 中,min_length、max_length这类字符串约束是原生str类型内置校验链的逻辑,不会自动挂载到自定义str子类上。
  • 重写__get_validators__方法后,该类型的校验流程完全由自定义逻辑接管。当前实现仅加入了「输入转字符串」的str_validator和自定义正则校验,既没有内置长度校验逻辑,也没有读取Field对象中传入的长度配置参数,因此配置的长度规则不会触发。
解决方案

以下两种方案都可以实现校验逻辑复用,不需要在每个字段重复编写校验规则:

方案1:在自定义类型中适配Field长度参数

修改Password类实现,在校验链中加入长度校验逻辑,自动读取Field配置的长度参数,同时支持设置默认长度约束:

from re import match
from typing import Callable
import pydantic
from pydantic.validators import str_validator
from pydantic.fields import ModelField

class Password(str):
    # 配置默认长度约束,字段无特殊配置时自动生效
    default_min_length: int = 8
    default_max_length: int = 128

    @classmethod
    def __get_validators__(cls) -> Callable:
        yield str_validator
        yield cls.validate_length
        yield cls.validate_pattern

    @classmethod
    def validate_length(cls, value: str, field: ModelField) -> str:
        # 优先读取Field传入的长度配置,无配置则使用类默认值
        min_len = field.field_info.min_length or cls.default_min_length
        max_len = field.field_info.max_length or cls.default_max_length
        val_len = len(value)
        if val_len < min_len:
            raise ValueError(f"Password length must be at least {min_len} characters")
        if val_len > max_len:
            raise ValueError(f"Password length cannot exceed {max_len} characters")
        return value

    @classmethod
    def validate_pattern(cls, value: str) -> str:
        regexp = (
            r"(?=.*?[a-z])"
            r"(?=.*?[A-Z])"
            r"(?=.*?[0-9])"
        )
        if not match(regexp, value):
            raise ValueError(
                "Password must contain at least one "
                "lower/upper case letter, one digit."
            )
        return value

该实现完全兼容原有写法,特殊场景下直接在Field中传入min_length/max_length即可覆盖默认长度规则。

方案2:继承Pydantic内置约束字符串类型

直接基于Pydantic自带的constr(约束字符串类型)实现,不需要自行编写长度校验逻辑,constr原生支持所有字符串约束的参数读取、校验和默认值覆盖逻辑:

from re import match
from typing import Callable
import pydantic
from pydantic import constr

# 定义带默认长度约束的密码基类
BasePassword = constr(min_length=8, max_length=128)

class Password(BasePassword):
    @classmethod
    def __get_validators__(cls) -> Callable:
        # 先加载constr自带的所有校验(类型转换、长度校验等)
        yield from super().__get_validators__()
        # 追加自定义密码格式校验
        yield cls.validate_pattern

    @classmethod
    def validate_pattern(cls, value: str) -> str:
        regexp = (
            r"(?=.*?[a-z])"
            r"(?=.*?[A-Z])"
            r"(?=.*?[0-9])"
        )
        if not match(regexp, value):
            raise ValueError(
                "Password must contain at least one "
                "lower/upper case letter, one digit."
            )
        return value

该方案行为和原生字符串类型完全一致,代码更简洁,不需要手动处理字段参数读取逻辑。

内容的提问来源于stack exchange,提问作者Michael Aboryone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:06:16