跳到内容

标准库类型

Pydantic 支持许多来自 Python 标准库的常用类型。如果您需要更严格的处理,请参阅 严格类型,包括如果您需要约束允许的值(例如,要求正数 int)。

注意

Pydantic 仍然支持较旧的(3.8-)类型构造,如 typing.Listtyping.Dict,但最佳实践是使用较新的类型,如 listdict

布尔值

如果值不是以下之一,则标准 bool 字段将引发 ValidationError

  • 有效的布尔值(即 TrueFalse),
  • 整数 01
  • 一个 str,当转换为小写时,是 '0''off''f''false''n''no''1''on''t''true''y''yes' 之一
  • 一个 bytes,当解码为 str 时,根据之前的规则有效

注意

如果您想要更严格的布尔逻辑(例如,一个仅允许 TrueFalse 的字段),您可以使用 StrictBool

这是一个演示其中一些行为的脚本

from pydantic import BaseModel, ValidationError


class BooleanModel(BaseModel):
    bool_value: bool


print(BooleanModel(bool_value=False))
#> bool_value=False
print(BooleanModel(bool_value='False'))
#> bool_value=False
print(BooleanModel(bool_value=1))
#> bool_value=True
try:
    BooleanModel(bool_value=[])
except ValidationError as e:
    print(str(e))
    """
    1 validation error for BooleanModel
    bool_value
      Input should be a valid boolean [type=bool_type, input_value=[], input_type=list]
    """

日期时间类型

Pydantic 支持以下 日期时间 类型

datetime.datetime

  • datetime 字段将接受以下类型的值

    • datetime;现有的 datetime 对象
    • intfloat;假定为 Unix 时间,即自 1970 年 1 月 1 日以来的秒数(如果 >= -2e10 且 <= 2e10)或毫秒数(如果 < -2e10 或 > 2e10
    • str;接受以下格式
      • YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z 或 [±]HH[:]MM]
      • YYYY-MM-DD 在宽松模式下被接受,但在严格模式下不被接受
      • intfloat 作为字符串(假定为 Unix 时间)
    • datetime.date 实例在宽松模式下被接受,但在严格模式下不被接受
from datetime import datetime

from pydantic import BaseModel


class Event(BaseModel):
    dt: datetime = None


event = Event(dt='2032-04-23T10:20:30.400+02:30')

print(event.model_dump())
"""
{'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000, tzinfo=TzInfo(+02:30))}
"""

datetime.date

  • date 字段将接受以下类型的值

    • date;现有的 date 对象
    • intfloat;处理方式与上面 datetime 的描述相同
    • str;接受以下格式
      • YYYY-MM-DD
      • intfloat 作为字符串(假定为 Unix 时间)
from datetime import date

from pydantic import BaseModel


class Birthday(BaseModel):
    d: date = None


my_birthday = Birthday(d=1679616000.0)

print(my_birthday.model_dump())
#> {'d': datetime.date(2023, 3, 24)}

datetime.time

  • time 字段将接受以下类型的值

    • time;现有的 time 对象
    • str;接受以下格式
      • HH:MM[:SS[.ffffff]][Z 或 [±]HH[:]MM]
from datetime import time

from pydantic import BaseModel


class Meeting(BaseModel):
    t: time = None


m = Meeting(t=time(4, 8, 16))

print(m.model_dump())
#> {'t': datetime.time(4, 8, 16)}

datetime.timedelta

  • timedelta 字段将接受以下类型的值

    • timedelta;现有的 timedelta 对象
    • intfloat;假定为秒
    • str;接受以下格式
      • [-][[DD]D,]HH:MM:SS[.ffffff]
        • 例如:'1d,01:02:03.000004''1D01:02:03.000004''01:02:03'
      • [±]P[DD]DT[HH]H[MM]M[SS]S (ISO 8601 timedelta 格式)
from datetime import timedelta

from pydantic import BaseModel


class Model(BaseModel):
    td: timedelta = None


m = Model(td='P3DT12H30M5S')

print(m.model_dump())
#> {'td': datetime.timedelta(days=3, seconds=45005)}

数字类型

Pydantic 支持来自 Python 标准库的以下数字类型

int

  • Pydantic 使用 int(v) 将类型强制转换为 int;有关数据转换期间信息丢失的详细信息,请参阅 数据转换

float

  • Pydantic 使用 float(v) 将值强制转换为浮点数。

enum.IntEnum

  • 验证:Pydantic 检查该值是否为有效的 IntEnum 实例。
  • enum.IntEnum 子类的验证:检查该值是否为整数枚举的有效成员;有关更多详细信息,请参阅 枚举和选择

decimal.Decimal

  • 验证:Pydantic 尝试将值转换为字符串,然后将字符串传递给 Decimal(v)
  • 序列化:Pydantic 将 Decimal 类型序列化为字符串。如果需要,您可以使用自定义序列化器来覆盖此行为。例如
from decimal import Decimal
from typing import Annotated

from pydantic import BaseModel, PlainSerializer


class Model(BaseModel):
    x: Decimal
    y: Annotated[
        Decimal,
        PlainSerializer(
            lambda x: float(x), return_type=float, when_used='json'
        ),
    ]


my_model = Model(x=Decimal('1.1'), y=Decimal('2.1'))

print(my_model.model_dump())  # (1)!
#> {'x': Decimal('1.1'), 'y': Decimal('2.1')}
print(my_model.model_dump(mode='json'))  # (2)!
#> {'x': '1.1', 'y': 2.1}
print(my_model.model_dump_json())  # (3)!
#> {"x":"1.1","y":2.1}
  1. 使用 model_dumpxy 都保持 Decimal 类型的实例
  2. 使用 mode='json'model_dumpx 被序列化为 string,而 y 由于应用了自定义序列化器而被序列化为 float
  3. 使用 model_dump_jsonx 被序列化为 string,而 y 由于应用了自定义序列化器而被序列化为 float

complex

  • 验证:Pydantic 支持 complex 类型或可以转换为 complex 类型的 str 值。
  • 序列化:Pydantic 将 complex 类型序列化为字符串。

fractions.Fraction

  • 验证:Pydantic 尝试使用 Fraction(v) 将值转换为 Fraction
  • 序列化:Pydantic 将 Fraction 类型序列化为字符串。

Enum

Pydantic 使用 Python 的标准 enum 类来定义选择。

enum.Enum 检查该值是否为有效的 Enum 实例。enum.Enum 的子类检查该值是否为枚举的有效成员。

from enum import Enum, IntEnum

from pydantic import BaseModel, ValidationError


class FruitEnum(str, Enum):
    pear = 'pear'
    banana = 'banana'


class ToolEnum(IntEnum):
    spanner = 1
    wrench = 2


class CookingModel(BaseModel):
    fruit: FruitEnum = FruitEnum.pear
    tool: ToolEnum = ToolEnum.spanner


print(CookingModel())
#> fruit=<FruitEnum.pear: 'pear'> tool=<ToolEnum.spanner: 1>
print(CookingModel(tool=2, fruit='banana'))
#> fruit=<FruitEnum.banana: 'banana'> tool=<ToolEnum.wrench: 2>
try:
    CookingModel(fruit='other')
except ValidationError as e:
    print(e)
    """
    1 validation error for CookingModel
    fruit
      Input should be 'pear' or 'banana' [type=enum, input_value='other', input_type=str]
    """

列表和元组

list

允许 listtuplesetfrozensetdeque 或生成器,并强制转换为 list。当提供泛型参数时,适当的验证将应用于列表的所有项。

from typing import Optional

from pydantic import BaseModel


class Model(BaseModel):
    simple_list: Optional[list] = None
    list_of_ints: Optional[list[int]] = None


print(Model(simple_list=['1', '2', '3']).simple_list)
#> ['1', '2', '3']
print(Model(list_of_ints=['1', '2', '3']).list_of_ints)
#> [1, 2, 3]
from pydantic import BaseModel


class Model(BaseModel):
    simple_list: list | None = None
    list_of_ints: list[int] | None = None


print(Model(simple_list=['1', '2', '3']).simple_list)
#> ['1', '2', '3']
print(Model(list_of_ints=['1', '2', '3']).list_of_ints)
#> [1, 2, 3]

tuple

允许 listtuplesetfrozensetdeque 或生成器,并强制转换为 tuple。当提供泛型参数时,适当的验证将应用于元组的各个项

typing.Tuple

处理方式与上面的 tuple 相同。

from typing import Optional

from pydantic import BaseModel


class Model(BaseModel):
    simple_tuple: Optional[tuple] = None
    tuple_of_different_types: Optional[tuple[int, float, bool]] = None


print(Model(simple_tuple=[1, 2, 3, 4]).simple_tuple)
#> (1, 2, 3, 4)
print(Model(tuple_of_different_types=[3, 2, 1]).tuple_of_different_types)
#> (3, 2.0, True)
from pydantic import BaseModel


class Model(BaseModel):
    simple_tuple: tuple | None = None
    tuple_of_different_types: tuple[int, float, bool] | None = None


print(Model(simple_tuple=[1, 2, 3, 4]).simple_tuple)
#> (1, 2, 3, 4)
print(Model(tuple_of_different_types=[3, 2, 1]).tuple_of_different_types)
#> (3, 2.0, True)

typing.NamedTuple

typing.NamedTuple 的子类类似于 tuple,但会创建给定 namedtuple 类的实例。

collections.namedtuple 的子类类似于 typing.NamedTuple 的子类,但由于未指定字段类型,因此所有字段都被视为具有 Any 类型。

from typing import NamedTuple

from pydantic import BaseModel, ValidationError


class Point(NamedTuple):
    x: int
    y: int


class Model(BaseModel):
    p: Point


try:
    Model(p=('1.3', '2'))
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    p.0
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='1.3', input_type=str]
    """

双端队列

deque

允许 listtuplesetfrozensetdeque 或生成器,并强制转换为 deque。当提供泛型参数时,适当的验证将应用于 deque 的各个项。

typing.Deque

处理方式与上面的 deque 相同。

from typing import Deque, Optional

from pydantic import BaseModel


class Model(BaseModel):
    deque: Optional[Deque[int]] = None


print(Model(deque=[1, 2, 3]).deque)
#> deque([1, 2, 3])
from typing import Deque

from pydantic import BaseModel


class Model(BaseModel):
    deque: Deque[int] | None = None


print(Model(deque=[1, 2, 3]).deque)
#> deque([1, 2, 3])

集合

set

允许 listtuplesetfrozensetdeque 或生成器,并强制转换为 set。当提供泛型参数时,适当的验证将应用于集合的所有项。

typing.Set

处理方式与上面的 set 相同。

from typing import Optional, Set

from pydantic import BaseModel


class Model(BaseModel):
    simple_set: Optional[set] = None
    set_of_ints: Optional[Set[int]] = None


print(Model(simple_set={'1', '2', '3'}).simple_set)
#> {'1', '2', '3'}
print(Model(simple_set=['1', '2', '3']).simple_set)
#> {'1', '2', '3'}
print(Model(set_of_ints=['1', '2', '3']).set_of_ints)
#> {1, 2, 3}
from pydantic import BaseModel


class Model(BaseModel):
    simple_set: set | None = None
    set_of_ints: set[int] | None = None


print(Model(simple_set={'1', '2', '3'}).simple_set)
#> {'1', '2', '3'}
print(Model(simple_set=['1', '2', '3']).simple_set)
#> {'1', '2', '3'}
print(Model(set_of_ints=['1', '2', '3']).set_of_ints)
#> {1, 2, 3}

frozenset

允许 listtuplesetfrozensetdeque 或生成器,并强制转换为 frozenset。当提供泛型参数时,适当的验证将应用于冻结集合的所有项。

typing.FrozenSet

处理方式与上面的 frozenset 相同。

from typing import FrozenSet, Optional

from pydantic import BaseModel


class Model(BaseModel):
    simple_frozenset: Optional[frozenset] = None
    frozenset_of_ints: Optional[FrozenSet[int]] = None


m1 = Model(simple_frozenset=['1', '2', '3'])
print(type(m1.simple_frozenset))
#> <class 'frozenset'>
print(sorted(m1.simple_frozenset))
#> ['1', '2', '3']

m2 = Model(frozenset_of_ints=['1', '2', '3'])
print(type(m2.frozenset_of_ints))
#> <class 'frozenset'>
print(sorted(m2.frozenset_of_ints))
#> [1, 2, 3]
from pydantic import BaseModel


class Model(BaseModel):
    simple_frozenset: frozenset | None = None
    frozenset_of_ints: frozenset[int] | None = None


m1 = Model(simple_frozenset=['1', '2', '3'])
print(type(m1.simple_frozenset))
#> <class 'frozenset'>
print(sorted(m1.simple_frozenset))
#> ['1', '2', '3']

m2 = Model(frozenset_of_ints=['1', '2', '3'])
print(type(m2.frozenset_of_ints))
#> <class 'frozenset'>
print(sorted(m2.frozenset_of_ints))
#> [1, 2, 3]

其他可迭代对象

typing.Sequence

这旨在用于当提供的值应满足 Sequence ABC 的要求,并且希望对容器中的值进行主动验证时。请注意,当必须对容器的值执行验证时,容器的类型可能无法保留,因为验证最终可能会替换值。我们保证验证后的值将是有效的 typing.Sequence,但它可能具有与提供的值不同的类型(通常,它将变为 list)。

typing.Iterable

这旨在用于当提供的值可能是不应被消耗的可迭代对象时。有关解析和验证的更多详细信息,请参阅下面的 无限生成器。与 typing.Sequence 类似,我们保证验证后的结果将是有效的 typing.Iterable,但它可能具有与提供的值不同的类型。特别是,即使提供了非生成器类型(如 list),类型为 typing.Iterable 的字段的验证后值也将是一个生成器。

这是一个使用 typing.Sequence 的简单示例

from typing import Sequence

from pydantic import BaseModel


class Model(BaseModel):
    sequence_of_ints: Sequence[int] = None


print(Model(sequence_of_ints=[1, 2, 3, 4]).sequence_of_ints)
#> [1, 2, 3, 4]
print(Model(sequence_of_ints=(1, 2, 3, 4)).sequence_of_ints)
#> (1, 2, 3, 4)
from collections.abc import Sequence

from pydantic import BaseModel


class Model(BaseModel):
    sequence_of_ints: Sequence[int] = None


print(Model(sequence_of_ints=[1, 2, 3, 4]).sequence_of_ints)
#> [1, 2, 3, 4]
print(Model(sequence_of_ints=(1, 2, 3, 4)).sequence_of_ints)
#> (1, 2, 3, 4)

无限生成器

如果您有一个想要验证的生成器,您仍然可以使用上面描述的 Sequence。在这种情况下,生成器将被消耗并作为列表存储在模型上,并且其值将根据 Sequence 的类型参数(例如 Sequence[int] 中的 int)进行验证。

但是,如果您有一个不希望被主动消耗的生成器(例如,无限生成器或远程数据加载器),您可以使用 Iterable 类型的字段

from typing import Iterable

from pydantic import BaseModel


class Model(BaseModel):
    infinite: Iterable[int]


def infinite_ints():
    i = 0
    while True:
        yield i
        i += 1


m = Model(infinite=infinite_ints())
print(m)
"""
infinite=ValidatorIterator(index=0, schema=Some(Int(IntValidator { strict: false })))
"""

for i in m.infinite:
    print(i)
    #> 0
    #> 1
    #> 2
    #> 3
    #> 4
    #> 5
    #> 6
    #> 7
    #> 8
    #> 9
    #> 10
    if i == 10:
        break
from collections.abc import Iterable

from pydantic import BaseModel


class Model(BaseModel):
    infinite: Iterable[int]


def infinite_ints():
    i = 0
    while True:
        yield i
        i += 1


m = Model(infinite=infinite_ints())
print(m)
"""
infinite=ValidatorIterator(index=0, schema=Some(Int(IntValidator { strict: false })))
"""

for i in m.infinite:
    print(i)
    #> 0
    #> 1
    #> 2
    #> 3
    #> 4
    #> 5
    #> 6
    #> 7
    #> 8
    #> 9
    #> 10
    if i == 10:
        break

警告

在初始验证期间,Iterable 字段仅执行一个简单的检查,即提供的参数是可迭代的。为了防止它被消耗,不会主动执行对生成值的验证。

尽管生成的值不会被主动验证,但它们在生成时仍会被验证,并在适当的时候在生成时引发 ValidationError

from typing import Iterable

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    int_iterator: Iterable[int]


def my_iterator():
    yield 13
    yield '27'
    yield 'a'


m = Model(int_iterator=my_iterator())
print(next(m.int_iterator))
#> 13
print(next(m.int_iterator))
#> 27
try:
    next(m.int_iterator)
except ValidationError as e:
    print(e)
    """
    1 validation error for ValidatorIterator
    2
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    """
from collections.abc import Iterable

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    int_iterator: Iterable[int]


def my_iterator():
    yield 13
    yield '27'
    yield 'a'


m = Model(int_iterator=my_iterator())
print(next(m.int_iterator))
#> 13
print(next(m.int_iterator))
#> 27
try:
    next(m.int_iterator)
except ValidationError as e:
    print(e)
    """
    1 validation error for ValidatorIterator
    2
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    """

映射类型

dict

dict(v) 用于尝试转换字典。

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    x: dict[str, int]


m = Model(x={'foo': 1})
print(m.model_dump())
#> {'x': {'foo': 1}}

try:
    Model(x={'foo': '1'})
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    x
      Input should be a valid dictionary [type=dict_type, input_value='test', input_type=str]
    """

TypedDict

注意

这是 Python 3.8 中 Python 标准库的新功能。由于 3.12 之前的 typing.TypedDict 存在限制,因此 Python <3.12 需要 typing-extensions 包。您需要从 typing_extensions 而不是 typing 导入 TypedDict,否则会收到构建时错误。

TypedDict 声明了一种字典类型,该类型期望其所有实例都具有一组特定的键,其中每个键都与一致类型的值相关联。

它与 dict 相同,但 Pydantic 将验证字典,因为键被注解。

from typing_extensions import TypedDict

from pydantic import TypeAdapter, ValidationError


class User(TypedDict):
    name: str
    id: int


ta = TypeAdapter(User)

print(ta.validate_python({'name': 'foo', 'id': 1}))
#> {'name': 'foo', 'id': 1}

try:
    ta.validate_python({'name': 'foo'})
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    id
      Field required [type=missing, input_value={'name': 'foo'}, input_type=dict]
    """
from typing import TypedDict

from pydantic import TypeAdapter, ValidationError


class User(TypedDict):
    name: str
    id: int


ta = TypeAdapter(User)

print(ta.validate_python({'name': 'foo', 'id': 1}))
#> {'name': 'foo', 'id': 1}

try:
    ta.validate_python({'name': 'foo'})
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    id
      Field required [type=missing, input_value={'name': 'foo'}, input_type=dict]
    """

您可以定义 __pydantic_config__ 来更改从 TypedDict 继承的模型。有关更多详细信息,请参阅 ConfigDict API 参考

from typing import Optional

from typing_extensions import TypedDict

from pydantic import ConfigDict, TypeAdapter, ValidationError


# `total=False` means keys are non-required
class UserIdentity(TypedDict, total=False):
    name: Optional[str]
    surname: str


class User(TypedDict):
    __pydantic_config__ = ConfigDict(extra='forbid')

    identity: UserIdentity
    age: int


ta = TypeAdapter(User)

print(
    ta.validate_python(
        {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}

print(
    ta.validate_python(
        {'identity': {'name': None, 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': None, 'surname': 'John'}, 'age': 37}

print(ta.validate_python({'identity': {}, 'age': 37}))
#> {'identity': {}, 'age': 37}


try:
    ta.validate_python(
        {'identity': {'name': ['Smith'], 'surname': 'John'}, 'age': 24}
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    identity.name
      Input should be a valid string [type=string_type, input_value=['Smith'], input_type=list]
    """

try:
    ta.validate_python(
        {
            'identity': {'name': 'Smith', 'surname': 'John'},
            'age': '37',
            'email': '[email protected]',
        }
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    email
      Extra inputs are not permitted [type=extra_forbidden, input_value='[email protected]', input_type=str]
    """
from typing_extensions import TypedDict

from pydantic import ConfigDict, TypeAdapter, ValidationError


# `total=False` means keys are non-required
class UserIdentity(TypedDict, total=False):
    name: str | None
    surname: str


class User(TypedDict):
    __pydantic_config__ = ConfigDict(extra='forbid')

    identity: UserIdentity
    age: int


ta = TypeAdapter(User)

print(
    ta.validate_python(
        {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}

print(
    ta.validate_python(
        {'identity': {'name': None, 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': None, 'surname': 'John'}, 'age': 37}

print(ta.validate_python({'identity': {}, 'age': 37}))
#> {'identity': {}, 'age': 37}


try:
    ta.validate_python(
        {'identity': {'name': ['Smith'], 'surname': 'John'}, 'age': 24}
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    identity.name
      Input should be a valid string [type=string_type, input_value=['Smith'], input_type=list]
    """

try:
    ta.validate_python(
        {
            'identity': {'name': 'Smith', 'surname': 'John'},
            'age': '37',
            'email': '[email protected]',
        }
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    email
      Extra inputs are not permitted [type=extra_forbidden, input_value='[email protected]', input_type=str]
    """
from typing import TypedDict

from pydantic import ConfigDict, TypeAdapter, ValidationError


# `total=False` means keys are non-required
class UserIdentity(TypedDict, total=False):
    name: str | None
    surname: str


class User(TypedDict):
    __pydantic_config__ = ConfigDict(extra='forbid')

    identity: UserIdentity
    age: int


ta = TypeAdapter(User)

print(
    ta.validate_python(
        {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': 'Smith', 'surname': 'John'}, 'age': 37}

print(
    ta.validate_python(
        {'identity': {'name': None, 'surname': 'John'}, 'age': 37}
    )
)
#> {'identity': {'name': None, 'surname': 'John'}, 'age': 37}

print(ta.validate_python({'identity': {}, 'age': 37}))
#> {'identity': {}, 'age': 37}


try:
    ta.validate_python(
        {'identity': {'name': ['Smith'], 'surname': 'John'}, 'age': 24}
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    identity.name
      Input should be a valid string [type=string_type, input_value=['Smith'], input_type=list]
    """

try:
    ta.validate_python(
        {
            'identity': {'name': 'Smith', 'surname': 'John'},
            'age': '37',
            'email': '[email protected]',
        }
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for User
    email
      Extra inputs are not permitted [type=extra_forbidden, input_value='[email protected]', input_type=str]
    """

可调用对象

有关解析和验证的更多详细信息,请参见下文

字段也可以是 Callable 类型

from typing import Callable

from pydantic import BaseModel


class Foo(BaseModel):
    callback: Callable[[int], int]


m = Foo(callback=lambda x: x)
print(m)
#> callback=<function <lambda> at 0x0123456789ab>
from collections.abc import Callable

from pydantic import BaseModel


class Foo(BaseModel):
    callback: Callable[[int], int]


m = Foo(callback=lambda x: x)
print(m)
#> callback=<function <lambda> at 0x0123456789ab>

警告

Callable 字段仅执行一个简单的检查,即参数是可调用的;不执行对参数、其类型或返回类型的验证。

IP 地址类型

有关其他自定义 IP 地址类型,请参阅 网络类型

UUID

对于 UUID,Pydantic 尝试使用类型本身进行验证,方法是将值传递给 UUID(v)。对于 bytesbytearray,有一个回退到 UUID(bytes=v)

如果您想约束 UUID 版本,可以检查以下类型

  • UUID1:需要 UUID 版本 1。
  • UUID3:需要 UUID 版本 3。
  • UUID4:需要 UUID 版本 4。
  • UUID5:需要 UUID 版本 5。

联合类型

Pydantic 对联合类型验证有广泛的支持,typing.Union 和 Python 3.10 的管道语法 (A | B) 都受支持。在 Unions 概念文档的章节中阅读更多内容。

type

Pydantic 支持使用 type[T] 来指定字段可能只接受 T 的子类(而不是实例)。

from pydantic import BaseModel, ValidationError


class Foo:
    pass


class Bar(Foo):
    pass


class Other:
    pass


class SimpleModel(BaseModel):
    just_subclasses: type[Foo]


SimpleModel(just_subclasses=Foo)
SimpleModel(just_subclasses=Bar)
try:
    SimpleModel(just_subclasses=Other)
except ValidationError as e:
    print(e)
    """
    1 validation error for SimpleModel
    just_subclasses
      Input should be a subclass of Foo [type=is_subclass_of, input_value=<class '__main__.Other'>, input_type=type]
    """

您也可以使用 type 来指定允许任何类。

from pydantic import BaseModel, ValidationError


class Foo:
    pass


class LenientSimpleModel(BaseModel):
    any_class_goes: type


LenientSimpleModel(any_class_goes=int)
LenientSimpleModel(any_class_goes=Foo)
try:
    LenientSimpleModel(any_class_goes=Foo())
except ValidationError as e:
    print(e)
    """
    1 validation error for LenientSimpleModel
    any_class_goes
      Input should be a type [type=is_type, input_value=<__main__.Foo object at 0x0123456789ab>, input_type=Foo]
    """

typing.TypeVar

TypeVar 支持无约束、约束或带边界。

from typing import TypeVar

from pydantic import BaseModel

Foobar = TypeVar('Foobar')
BoundFloat = TypeVar('BoundFloat', bound=float)
IntStr = TypeVar('IntStr', int, str)


class Model(BaseModel):
    a: Foobar  # equivalent of ": Any"
    b: BoundFloat  # equivalent of ": float"
    c: IntStr  # equivalent of ": Union[int, str]"


print(Model(a=[1], b=4.2, c='x'))
#> a=[1] b=4.2 c='x'

# a may be None
print(Model(a=None, b=1, c=1))
#> a=None b=1.0 c=1

None 类型

Nonetype(None)Literal[None] 根据 类型规范 都是等效的。仅允许 None 值。

字符串

  • str:字符串按原样接受。
  • bytesbytearray 使用 decode() 方法转换。
  • str 继承的枚举使用 value 属性转换。

所有其他类型都会导致错误。

字符串不是序列

虽然从类型检查器的角度来看,str 的实例在技术上是 Sequence[str] 协议的有效实例,但这通常不是预期的,并且是错误的常见来源。

因此,如果您尝试将 strbytes 实例传递到 Sequence[str]Sequence[bytes] 类型的字段中,Pydantic 会引发 ValidationError

from typing import Optional, Sequence

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    sequence_of_strs: Optional[Sequence[str]] = None
    sequence_of_bytes: Optional[Sequence[bytes]] = None


print(Model(sequence_of_strs=['a', 'bc']).sequence_of_strs)
#> ['a', 'bc']
print(Model(sequence_of_strs=('a', 'bc')).sequence_of_strs)
#> ('a', 'bc')
print(Model(sequence_of_bytes=[b'a', b'bc']).sequence_of_bytes)
#> [b'a', b'bc']
print(Model(sequence_of_bytes=(b'a', b'bc')).sequence_of_bytes)
#> (b'a', b'bc')


try:
    Model(sequence_of_strs='abc')
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    sequence_of_strs
      'str' instances are not allowed as a Sequence value [type=sequence_str, input_value='abc', input_type=str]
    """
try:
    Model(sequence_of_bytes=b'abc')
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    sequence_of_bytes
      'bytes' instances are not allowed as a Sequence value [type=sequence_str, input_value=b'abc', input_type=bytes]
    """
from collections.abc import Sequence

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    sequence_of_strs: Sequence[str] | None = None
    sequence_of_bytes: Sequence[bytes] | None = None


print(Model(sequence_of_strs=['a', 'bc']).sequence_of_strs)
#> ['a', 'bc']
print(Model(sequence_of_strs=('a', 'bc')).sequence_of_strs)
#> ('a', 'bc')
print(Model(sequence_of_bytes=[b'a', b'bc']).sequence_of_bytes)
#> [b'a', b'bc']
print(Model(sequence_of_bytes=(b'a', b'bc')).sequence_of_bytes)
#> (b'a', b'bc')


try:
    Model(sequence_of_strs='abc')
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    sequence_of_strs
      'str' instances are not allowed as a Sequence value [type=sequence_str, input_value='abc', input_type=str]
    """
try:
    Model(sequence_of_bytes=b'abc')
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    sequence_of_bytes
      'bytes' instances are not allowed as a Sequence value [type=sequence_str, input_value=b'abc', input_type=bytes]
    """

字节

bytes 按原样接受。bytearray 使用 bytes(v) 转换。str 使用 v.encode() 转换。intfloatDecimal 使用 str(v).encode() 强制转换。有关更多详细信息,请参阅 ByteSize

typing.Literal

Pydantic 支持使用 typing.Literal 作为一种轻量级的方式来指定字段可能只接受特定的字面值

from typing import Literal

from pydantic import BaseModel, ValidationError


class Pie(BaseModel):
    flavor: Literal['apple', 'pumpkin']


Pie(flavor='apple')
Pie(flavor='pumpkin')
try:
    Pie(flavor='cherry')
except ValidationError as e:
    print(str(e))
    """
    1 validation error for Pie
    flavor
      Input should be 'apple' or 'pumpkin' [type=literal_error, input_value='cherry', input_type=str]
    """

此字段类型的一个好处是,它可以用于检查与一个或多个特定值的相等性,而无需声明自定义验证器

from typing import ClassVar, Literal, Union

from pydantic import BaseModel, ValidationError


class Cake(BaseModel):
    kind: Literal['cake']
    required_utensils: ClassVar[list[str]] = ['fork', 'knife']


class IceCream(BaseModel):
    kind: Literal['icecream']
    required_utensils: ClassVar[list[str]] = ['spoon']


class Meal(BaseModel):
    dessert: Union[Cake, IceCream]


print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Cake
print(type(Meal(dessert={'kind': 'icecream'}).dessert).__name__)
#> IceCream
try:
    Meal(dessert={'kind': 'pie'})
except ValidationError as e:
    print(str(e))
    """
    2 validation errors for Meal
    dessert.Cake.kind
      Input should be 'cake' [type=literal_error, input_value='pie', input_type=str]
    dessert.IceCream.kind
      Input should be 'icecream' [type=literal_error, input_value='pie', input_type=str]
    """
from typing import ClassVar, Literal

from pydantic import BaseModel, ValidationError


class Cake(BaseModel):
    kind: Literal['cake']
    required_utensils: ClassVar[list[str]] = ['fork', 'knife']


class IceCream(BaseModel):
    kind: Literal['icecream']
    required_utensils: ClassVar[list[str]] = ['spoon']


class Meal(BaseModel):
    dessert: Cake | IceCream


print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Cake
print(type(Meal(dessert={'kind': 'icecream'}).dessert).__name__)
#> IceCream
try:
    Meal(dessert={'kind': 'pie'})
except ValidationError as e:
    print(str(e))
    """
    2 validation errors for Meal
    dessert.Cake.kind
      Input should be 'cake' [type=literal_error, input_value='pie', input_type=str]
    dessert.IceCream.kind
      Input should be 'icecream' [type=literal_error, input_value='pie', input_type=str]
    """

通过在注解的 Union 中适当排序,您可以使用它来解析特异性递减的类型

from typing import Literal, Optional, Union

from pydantic import BaseModel


class Dessert(BaseModel):
    kind: str


class Pie(Dessert):
    kind: Literal['pie']
    flavor: Optional[str]


class ApplePie(Pie):
    flavor: Literal['apple']


class PumpkinPie(Pie):
    flavor: Literal['pumpkin']


class Meal(BaseModel):
    dessert: Union[ApplePie, PumpkinPie, Pie, Dessert]


print(type(Meal(dessert={'kind': 'pie', 'flavor': 'apple'}).dessert).__name__)
#> ApplePie
print(type(Meal(dessert={'kind': 'pie', 'flavor': 'pumpkin'}).dessert).__name__)
#> PumpkinPie
print(type(Meal(dessert={'kind': 'pie'}).dessert).__name__)
#> Dessert
print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Dessert
from typing import Literal

from pydantic import BaseModel


class Dessert(BaseModel):
    kind: str


class Pie(Dessert):
    kind: Literal['pie']
    flavor: str | None


class ApplePie(Pie):
    flavor: Literal['apple']


class PumpkinPie(Pie):
    flavor: Literal['pumpkin']


class Meal(BaseModel):
    dessert: ApplePie | PumpkinPie | Pie | Dessert


print(type(Meal(dessert={'kind': 'pie', 'flavor': 'apple'}).dessert).__name__)
#> ApplePie
print(type(Meal(dessert={'kind': 'pie', 'flavor': 'pumpkin'}).dessert).__name__)
#> PumpkinPie
print(type(Meal(dessert={'kind': 'pie'}).dessert).__name__)
#> Dessert
print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Dessert

typing.Any

允许任何值,包括 None

typing.Hashable

  • 从 Python 来看,支持任何通过 isinstance(v, Hashable) 检查的数据。
  • 从 JSON 来看,首先通过 Any 验证器加载数据,然后检查数据是否可以通过 isinstance(v, Hashable) 进行哈希。

typing.Annotated

允许使用任意元数据包装另一种类型,如 PEP-593 所述。Annotated 提示可能包含对 Field 函数 的单个调用,但否则,其他元数据将被忽略,并且使用根类型。

typing.Pattern

将导致输入值传递给 re.compile(v) 以创建正则表达式模式。

pathlib.Path

简单地使用类型本身进行验证,方法是将值传递给 Path(v)