使用错误
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'
可调用鉴别器案例,无标签¶
当使用可调用的 Discriminator
的 Union
没有为所有情况提供 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()
Config
和 model_config
都定义了¶
当同时使用 class Config
和 model_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'
根验证器, pre
, skip_on_failure
¶
如果您使用 @root_validator
与 pre=False
(默认),则必须指定 skip_on_failure=True
。 skip_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'
validator
、 field
、 config
和 info
¶
field
和 config
参数在 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_validator
或 model_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'
config
与 TypeAdapter
未使用¶
如果您尝试将 config
传递给 TypeAdapter
,而类型是具有自身无法覆盖的配置的类型(目前这仅适用于 BaseModel
、 TypedDict
和 dataclass
),则会出现此错误:
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
init
和 extra
设置¶
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.
不兼容的 init
和 init_var
设置在 dataclass
字段上¶
init=False
和 init_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'
本文总阅读量次