跳转至

使用错误

Pydantic 试图提供有用的错误。以下各节详细介绍了开发人员在使用 Pydantic 时可能遇到的常见错误,并提供了解决错误情况的建议。

类未完全定义

当在 pydantic 验证类型的注释中引用的类型(例如 BaseModel 的子类,或 pydantic dataclass )未定义时,会引发此错误:

from typing import ForwardRef

from pydantic import BaseModel, PydanticUserError

UndefinedType = ForwardRef('UndefinedType')


class Foobar(BaseModel):
    a: UndefinedType


try:
    Foobar(a=1)
except PydanticUserError as exc_info:
    assert exc_info.code == 'class-not-fully-defined'

或者在使用后定义类型时:

from typing import Optional

from pydantic import BaseModel, PydanticUserError


class Foo(BaseModel):
    a: Optional['Bar'] = None


try:
    # this doesn't work, see raised error
    foo = Foo(a={'b': {'a': None}})
except PydanticUserError as exc_info:
    assert exc_info.code == 'class-not-fully-defined'


class Bar(BaseModel):
    b: 'Foo'


# this works, though
foo = Foo(a={'b': {'a': None}})

对于 BaseModel 的子类,可以通过定义类型然后调用 .model_rebuild() 来解决:

from typing import Optional

from pydantic import BaseModel


class Foo(BaseModel):
    a: Optional['Bar'] = None


class Bar(BaseModel):
    b: 'Foo'


Foo.model_rebuild()

foo = Foo(a={'b': {'a': None}})

在其他情况下,错误消息应指出如何使用适当定义的类型重建类。

自定义 JSON 模式

__modify_schema__ 方法在 V2 中不再受支持。您应该使用 __get_pydantic_json_schema__ 方法代替。

__modify_schema__ 用于接收一个表示 JSON 模式的参数。请参见下面的示例:

from pydantic import BaseModel, PydanticUserError

try:

    class Model(BaseModel):
        @classmethod
        def __modify_schema__(cls, field_schema):
            field_schema.update(examples='examples')

except PydanticUserError as exc_info:
    assert exc_info.code == 'custom-json-schema'

新方法 __get_pydantic_json_schema__ 接收两个参数:第一个是一个字典,用 CoreSchema 表示,第二个是一个可调用的 handler ,它接收一个 CoreSchema 作为参数,并返回一个 JSON 模式。请参见下面的示例:

from typing import Any, Dict

from pydantic_core import CoreSchema

from pydantic import BaseModel, GetJsonSchemaHandler


class Model(BaseModel):
    @classmethod
    def __get_pydantic_json_schema__(
        cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler
    ) -> Dict[str, Any]:
        json_schema = super().__get_pydantic_json_schema__(core_schema, handler)
        json_schema = handler.resolve_ref_schema(json_schema)
        json_schema.update(examples='examples')
        return json_schema


print(Model.model_json_schema())
"""
{'examples': 'examples', 'properties': {}, 'title': 'Model', 'type': 'object'}
"""

缺少字段的修饰符

当你定义一个装饰器时,使用了一个无效的字段,就会引发这个错误。

from typing import Any

from pydantic import BaseModel, PydanticUserError, field_validator

try:

    class Model(BaseModel):
        a: str

        @field_validator('b')
        def check_b(cls, v: Any):
            return v

except PydanticUserError as exc_info:
    assert exc_info.code == 'decorator-missing-field'

如果您是从模型继承的并且打算这样做,可以使用 check_fields=False

from typing import Any

from pydantic import BaseModel, create_model, field_validator


class Model(BaseModel):
    @field_validator('a', check_fields=False)
    def check_a(cls, v: Any):
        return v


model = create_model('FooModel', a=(str, 'cake'), __base__=Model)

鉴别器没有字段

当 discriminated unions 中的模型没有定义鉴别器字段时会引发此错误。

from typing import Union

from typing_extensions import Literal

from pydantic import BaseModel, Field, PydanticUserError


class Cat(BaseModel):
    c: str


class Dog(BaseModel):
    pet_type: Literal['dog']
    d: str


try:

    class Model(BaseModel):
        pet: Union[Cat, Dog] = Field(..., discriminator='pet_type')
        number: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'discriminator-no-field'

鉴别器别名类型

当你在鉴别器字段上定义非字符串别名时会引发此错误。

from typing import Union

from typing_extensions import Literal

from pydantic import AliasChoices, BaseModel, Field, PydanticUserError


class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(
        validation_alias=AliasChoices('Pet', 'PET')
    )
    c: str


class Dog(BaseModel):
    pet_type: Literal['dog']
    d: str


try:

    class Model(BaseModel):
        pet: Union[Cat, Dog] = Field(..., discriminator='pet_type')
        number: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'discriminator-alias-type'

鉴别器需要文字

当你在鉴别器字段上定义非 Literal 类型时会引发此错误。

from typing import Union

from typing_extensions import Literal

from pydantic import BaseModel, Field, PydanticUserError


class Cat(BaseModel):
    pet_type: int
    c: str


class Dog(BaseModel):
    pet_type: Literal['dog']
    d: str


try:

    class Model(BaseModel):
        pet: Union[Cat, Dog] = Field(..., discriminator='pet_type')
        number: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'discriminator-needs-literal'

鉴别器别名

当你在鉴别器字段上定义不同的别名时会引发此错误。

from typing import Union

from typing_extensions import Literal

from pydantic import BaseModel, Field, PydanticUserError


class Cat(BaseModel):
    pet_type: Literal['cat'] = Field(validation_alias='PET')
    c: str


class Dog(BaseModel):
    pet_type: Literal['dog'] = Field(validation_alias='Pet')
    d: str


try:

    class Model(BaseModel):
        pet: Union[Cat, Dog] = Field(..., discriminator='pet_type')
        number: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'discriminator-alias'

无效的鉴别器验证器

当你在鉴别器字段上使用 before、wrap 或 plain 验证器时,会引发此错误。

这是不允许的,因为鉴别器字段用于确定用于验证的模型类型,所以你不能使用可能会更改其值的验证器。

from typing import Union

from typing_extensions import Literal

from pydantic import BaseModel, Field, PydanticUserError, field_validator


class Cat(BaseModel):
    pet_type: Literal['cat']

    @field_validator('pet_type', mode='before')
    @classmethod
    def validate_pet_type(cls, v):
        if v == 'kitten':
            return 'cat'
        return v


class Dog(BaseModel):
    pet_type: Literal['dog']


try:

    class Model(BaseModel):
        pet: Union[Cat, Dog] = Field(..., discriminator='pet_type')
        number: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'discriminator-validator'

这可以通过使用标准的 Union 来解决,丢弃鉴别器:

from typing import Union

from typing_extensions import Literal

from pydantic import BaseModel, field_validator


class Cat(BaseModel):
    pet_type: Literal['cat']

    @field_validator('pet_type', mode='before')
    @classmethod
    def validate_pet_type(cls, v):
        if v == 'kitten':
            return 'cat'
        return v


class Dog(BaseModel):
    pet_type: Literal['dog']


class Model(BaseModel):
    pet: Union[Cat, Dog]


assert Model(pet={'pet_type': 'kitten'}).pet.pet_type == 'cat'

可调用鉴别器案例,无标签

当使用可调用的 DiscriminatorUnion 没有为所有情况提供 Tag 注释时,会引发此错误。

from typing import Union

from typing_extensions import Annotated

from pydantic import BaseModel, Discriminator, PydanticUserError, Tag


def model_x_discriminator(v):
    if isinstance(v, str):
        return 'str'
    if isinstance(v, (dict, BaseModel)):
        return 'model'


# tag missing for both union choices
try:

    class DiscriminatedModel(BaseModel):
        x: Annotated[
            Union[str, 'DiscriminatedModel'],
            Discriminator(model_x_discriminator),
        ]

except PydanticUserError as exc_info:
    assert exc_info.code == 'callable-discriminator-no-tag'

# tag missing for `'DiscriminatedModel'` union choice
try:

    class DiscriminatedModel(BaseModel):
        x: Annotated[
            Union[Annotated[str, Tag('str')], 'DiscriminatedModel'],
            Discriminator(model_x_discriminator),
        ]

except PydanticUserError as exc_info:
    assert exc_info.code == 'callable-discriminator-no-tag'

# tag missing for `str` union choice
try:

    class DiscriminatedModel(BaseModel):
        x: Annotated[
            Union[str, Annotated['DiscriminatedModel', Tag('model')]],
            Discriminator(model_x_discriminator),
        ]

except PydanticUserError as exc_info:
    assert exc_info.code == 'callable-discriminator-no-tag'

TypedDict 版本

当你在 Python < 3.12 中使用 typing.TypedDict 而不是 typing_extensions.TypedDict 时,会引发此错误。

模型父字段覆盖

当基类上定义的字段被非注释属性覆盖时,会引发此错误。

from pydantic import BaseModel, PydanticUserError


class Foo(BaseModel):
    a: float


try:

    class Bar(Foo):
        x: float = 12.3
        a = 123.0

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-field-overridden'

模型字段缺少注释

当一个字段没有注释时,会引发此错误。

from pydantic import BaseModel, Field, PydanticUserError

try:

    class Model(BaseModel):
        a = Field('foobar')
        b = None

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-field-missing-annotation'

如果该字段并非有意设置为字段,那么通过将其标注为 ClassVar :,可能有助于解决该错误

from typing import ClassVar

from pydantic import BaseModel


class Model(BaseModel):
    a: ClassVar[str]

或者更新 model_config['ignored_types']

from pydantic import BaseModel, ConfigDict


class IgnoredType:
    pass


class MyModel(BaseModel):
    model_config = ConfigDict(ignored_types=(IgnoredType,))

    _a = IgnoredType()
    _b: int = IgnoredType()
    _c: IgnoredType
    _d: IgnoredType = IgnoredType()

Configmodel_config 都定义了

当同时使用 class Configmodel_config 时会引发此错误。

from pydantic import BaseModel, ConfigDict, PydanticUserError

try:

    class Model(BaseModel):
        model_config = ConfigDict(from_attributes=True)

        a: str

        class Config:
            from_attributes = True

except PydanticUserError as exc_info:
    assert exc_info.code == 'config-both'

已移除的关键字参数

当 Pydantic V2 中没有关键字参数时会引发此错误。

例如,Pydantic V2 中删除了 regex

from pydantic import BaseModel, Field, PydanticUserError

try:

    class Model(BaseModel):
        x: str = Field(regex='test')

except PydanticUserError as exc_info:
    assert exc_info.code == 'removed-kwargs'

JSON 模式无效类型

当 Pydantic 无法为某些 CoreSchema 生成 JSON 模式时,会引发此错误。

from pydantic import BaseModel, ImportString, PydanticUserError


class Model(BaseModel):
    a: ImportString


try:
    Model.model_json_schema()
except PydanticUserError as exc_info:
    assert exc_info.code == 'invalid-for-json-schema'

JSON 模式已使用

当 JSON 模式生成器已被用于生成 JSON 模式时,会引发此错误。您必须创建一个新实例来生成新的 JSON 模式。

基础模型实例化

当你直接实例化 BaseModel 时会引发此错误。Pydantic 模型应该从 BaseModel 继承。

from pydantic import BaseModel, PydanticUserError

try:
    BaseModel()
except PydanticUserError as exc_info:
    assert exc_info.code == 'base-model-instantiated'

未定义的注释

当在 CoreSchema 生成过程中处理未定义的注解时会引发此错误。

from pydantic import BaseModel, PydanticUndefinedAnnotation


class Model(BaseModel):
    a: 'B'  # noqa F821


try:
    Model.model_rebuild()
except PydanticUndefinedAnnotation as exc_info:
    assert exc_info.code == 'undefined-annotation'

未知类型的模式

当 Pydantic 无法为某些类型生成 CoreSchema 时,会引发此错误。

from pydantic import BaseModel, PydanticUserError

try:

    class Model(BaseModel):
        x: 43 = 123

except PydanticUserError as exc_info:
    assert exc_info.code == 'schema-for-unknown-type'

导入错误

当您尝试导入在 Pydantic V1 中可用但在 Pydantic V2 中已删除的对象时,会引发此错误。

请参阅迁移指南以获取更多信息。

create_model 字段定义

当您在 create_model 中提供无效的字段定义输入时,会引发此错误。

from pydantic import PydanticUserError, create_model

try:
    create_model('FooModel', foo=(str, 'default value', 'more'))
except PydanticUserError as exc_info:
    assert exc_info.code == 'create-model-field-definitions'

或者当你使用 [ typing.Annotated ][] 时输入无效

from typing_extensions import Annotated

from pydantic import PydanticUserError, create_model

try:
    create_model('FooModel', foo=Annotated[str, 'NotFieldInfoValue'])
except PydanticUserError as exc_info:
    assert exc_info.code == 'create-model-field-definitions'

create_model 配置基础

当你在 create_model 中同时使用 __config____base__ 时会引发此错误。

from pydantic import BaseModel, ConfigDict, PydanticUserError, create_model

try:
    config = ConfigDict(frozen=True)
    model = create_model(
        'FooModel', foo=(int, ...), __config__=config, __base__=BaseModel
    )
except PydanticUserError as exc_info:
    assert exc_info.code == 'create-model-config-base'

没有字段的验证器

当你使用 validator 时没有提供任何字段就会引发这个错误。

from pydantic import BaseModel, PydanticUserError, field_validator

try:

    class Model(BaseModel):
        a: str

        @field_validator
        def checker(cls, v):
            return v

except PydanticUserError as exc_info:
    assert exc_info.code == 'validator-no-fields'

validators 应与字段和关键字参数一起使用。

from pydantic import BaseModel, field_validator


class Model(BaseModel):
    a: str

    @field_validator('a')
    def checker(cls, v):
        return v

无效的验证器字段

当您使用带有非字符串字段的验证器时,会引发此错误。

from pydantic import BaseModel, PydanticUserError, field_validator

try:

    class Model(BaseModel):
        a: str
        b: str

        @field_validator(['a', 'b'])
        def check_fields(cls, v):
            return v

except PydanticUserError as exc_info:
    assert exc_info.code == 'validator-invalid-fields'

字段应作为单独的字符串参数传递:

from pydantic import BaseModel, field_validator


class Model(BaseModel):
    a: str
    b: str

    @field_validator('a', 'b')
    def check_fields(cls, v):
        return v

实例方法上的验证器

当你在实例方法上应用验证器时会引发此错误。

from pydantic import BaseModel, PydanticUserError, field_validator

try:

    class Model(BaseModel):
        a: int = 1

        @field_validator('a')
        def check_a(self, values):
            return values

except PydanticUserError as exc_info:
    assert exc_info.code == 'validator-instance-method'

根验证器, preskip_on_failure

如果您使用 @root_validatorpre=False (默认),则必须指定 skip_on_failure=Trueskip_on_failure=False 选项不再可用。

如果你不想设置 skip_on_failure=False ,你可以安全地设置 skip_on_failure=True 。如果这样做,那么如果任何字段的验证失败,这个根验证器将不再被调用。

请查看迁移指南以获取更多详细信息。

model_serializer 实例方法

@model_serializer 必须应用于实例方法。

当你在实例方法上应用 model_serializer 时,会引发此错误,而该实例方法没有 self

from pydantic import BaseModel, PydanticUserError, model_serializer

try:

    class MyModel(BaseModel):
        a: int

        @model_serializer
        def _serialize(slf, x, y, z):
            return slf

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-serializer-instance-method'

或者在类方法上:

from pydantic import BaseModel, PydanticUserError, model_serializer

try:

    class MyModel(BaseModel):
        a: int

        @model_serializer
        @classmethod
        def _serialize(self, x, y, z):
            return self

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-serializer-instance-method'

validatorfieldconfiginfo

fieldconfig 参数在 Pydantic V2 中不可用。请使用 info 参数代替。

你可以通过 info.config 访问配置,但它是一个字典,而不是像 Pydantic V1 中那样的对象。

field 号参数不再可用。

Pydantic V1 验证器签名

当你使用不支持的签名时,会引发此错误 Pydantic V1 风格的验证器。

import warnings

from pydantic import BaseModel, PydanticUserError, validator

warnings.filterwarnings('ignore', category=DeprecationWarning)

try:

    class Model(BaseModel):
        a: int

        @validator('a')
        def check_a(cls, value, foo):
            return value

except PydanticUserError as exc_info:
    assert exc_info.code == 'validator-v1-signature'

未识别的 field_validator 签名

field_validatormodel_validator 函数的签名不正确时会引发此错误。

from pydantic import BaseModel, PydanticUserError, field_validator

try:

    class Model(BaseModel):
        a: str

        @field_validator('a')
        @classmethod
        def check_a(cls):
            return 'a'

except PydanticUserError as exc_info:
    assert exc_info.code == 'validator-signature'

未识别的 field_serializer 签名

field_serializer 函数的签名不正确时会引发此错误。

from pydantic import BaseModel, PydanticUserError, field_serializer

try:

    class Model(BaseModel):
        x: int

        @field_serializer('x')
        def no_args():
            return 'x'

except PydanticUserError as exc_info:
    assert exc_info.code == 'field-serializer-signature'

有效的序列化程序签名是:

from pydantic import model_serializer

# an instance method with the default mode or `mode='plain'`
@model_serializer('x')  # or @serialize('x', mode='plain')
def ser_x(self, value: Any, info: pydantic.FieldSerializationInfo): ...

# a static method or free-standing function with the default mode or `mode='plain'`
@model_serializer('x')  # or @serialize('x', mode='plain')
@staticmethod
def ser_x(value: Any, info: pydantic.FieldSerializationInfo): ...
# equivalent to
def ser_x(value: Any, info: pydantic.FieldSerializationInfo): ...
serializer('x')(ser_x)

# an instance method with `mode='wrap'`
@model_serializer('x', mode='wrap')
def ser_x(self, value: Any, nxt: pydantic.SerializerFunctionWrapHandler, info: pydantic.FieldSerializationInfo): ...

# a static method or free-standing function with `mode='wrap'`
@model_serializer('x', mode='wrap')
@staticmethod
def ser_x(value: Any, nxt: pydantic.SerializerFunctionWrapHandler, info: pydantic.FieldSerializationInfo): ...
# equivalent to
def ser_x(value: Any, nxt: pydantic.SerializerFunctionWrapHandler, info: pydantic.FieldSerializationInfo): ...
serializer('x')(ser_x)

For all of these, you can also choose to omit the `info` argument, for example:

@model_serializer('x')
def ser_x(self, value: Any): ...

@model_serializer('x', mode='wrap')
def ser_x(self, value: Any, handler: pydantic.SerializerFunctionWrapHandler): ...

未识别的 model_serializer 签名

model_serializer 函数的签名不正确时会引发此错误。

from pydantic import BaseModel, PydanticUserError, model_serializer

try:

    class MyModel(BaseModel):
        a: int

        @model_serializer
        def _serialize(self, x, y, z):
            return self

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-serializer-signature'

多个字段序列化器

当为一个字段定义了多个 model_serializer 函数时,会引发此错误。

from pydantic import BaseModel, PydanticUserError, field_serializer

try:

    class MyModel(BaseModel):
        x: int
        y: int

        @field_serializer('x', 'y')
        def serializer1(v):
            return f'{v:,}'

        @field_serializer('x')
        def serializer2(v):
            return v

except PydanticUserError as exc_info:
    assert exc_info.code == 'multiple-field-serializers'

无效的注解类型

当注释无法注释类型时会引发此错误。

from typing_extensions import Annotated

from pydantic import BaseModel, FutureDate, PydanticUserError

try:

    class Model(BaseModel):
        foo: Annotated[str, FutureDate()]

except PydanticUserError as exc_info:
    assert exc_info.code == 'invalid-annotated-type'

configTypeAdapter 未使用

如果您尝试将 config 传递给 TypeAdapter ,而类型是具有自身无法覆盖的配置的类型(目前这仅适用于 BaseModelTypedDictdataclass ),则会出现此错误:

from typing_extensions import TypedDict

from pydantic import ConfigDict, PydanticUserError, TypeAdapter


class MyTypedDict(TypedDict):
    x: int


try:
    TypeAdapter(MyTypedDict, config=ConfigDict(strict=True))
except PydanticUserError as exc_info:
    assert exc_info.code == 'type-adapter-config-unused'

相反,你需要子类化该类型并覆盖或设置它的配置:

from typing_extensions import TypedDict

from pydantic import ConfigDict, TypeAdapter


class MyTypedDict(TypedDict):
    x: int

    # or `model_config = ...` for BaseModel
    __pydantic_config__ = ConfigDict(strict=True)


TypeAdapter(MyTypedDict)  # ok

不能指定 model_config['extra']RootModel

因为 RootModel 在初始化期间无法存储甚至接受额外的字段,所以如果您在创建 RootModel 的子类时尝试为 'extra' 的配置设置指定值,我们将引发错误:

from pydantic import PydanticUserError, RootModel

try:

    class MyRootModel(RootModel):
        model_config = {'extra': 'allow'}
        root: int

except PydanticUserError as exc_info:
    assert exc_info.code == 'root-model-extra'

无法评估类型注释

因为类型注解是在赋值后计算的,所以当使用与字段冲突的类型注解名称时,您可能会得到意外的结果。在以下情况下,我们会引发错误:

from datetime import date

from pydantic import BaseModel, Field


class Model(BaseModel):
    date: date = Field(description='A date')

作为一种解决方法,您可以使用别名或更改导入:

import datetime
# Or `from datetime import date as _date`

from pydantic import BaseModel, Field


class Model(BaseModel):
    date: datetime.date = Field(description='A date')

不兼容的 dataclass initextra 设置

Pydantic 不允许在数据类上指定 extra='allow' 设置,同时任何字段都设置了 init=False

因此,你可能不能做以下这样的事情:

from pydantic import ConfigDict, Field
from pydantic.dataclasses import dataclass


@dataclass(config=ConfigDict(extra='allow'))
class A:
    a: int = Field(init=False, default=1)

上述代码片段在为 A 数据类构建模式时会导致以下错误:

pydantic.errors.PydanticUserError: Field a has `init=False` and dataclass has config setting `extra="allow"`.
This combination is not allowed.

不兼容的 initinit_var 设置在 dataclass 字段上

init=Falseinit_var=True 的设置相互排斥。这样做会导致如下示例中显示的 PydanticUserError

from pydantic import Field
from pydantic.dataclasses import dataclass


@dataclass
class Foo:
    bar: str = Field(..., init=False, init_var=True)


"""
pydantic.errors.PydanticUserError: Dataclass field bar has init=False and init_var=True, but these are mutually exclusive.
"""

model_config 被用作模型字段

当使用 model_config 作为字段名称时会引发此错误。

from pydantic import BaseModel, PydanticUserError

try:

    class Model(BaseModel):
        model_config: str

except PydanticUserError as exc_info:
    assert exc_info.code == 'model-config-invalid-field-name'

with_config 用于一个 BaseModel 子类

当在一个已经是 Pydantic 模型的类上使用 with_config 装饰器时,会引发此错误(请使用 model_config 属性代替)。

from pydantic import BaseModel, PydanticUserError, with_config

try:

    @with_config({'allow_inf_nan': True})
    class Model(BaseModel):
        bar: str

except PydanticUserError as exc_info:
    assert exc_info.code == 'with-config-on-model'

dataclass 用于 BaseModel 子类

当在一个已经是 Pydantic 模型的类上使用 Pydantic dataclass 装饰器时,会引发此错误。

from pydantic import BaseModel, PydanticUserError
from pydantic.dataclasses import dataclass

try:

    @dataclass
    class Model(BaseModel):
        bar: str

except PydanticUserError as exc_info:
    assert exc_info.code == 'dataclass-on-model'

本文总阅读量