错误处理
每当 Pydantic 在验证数据时发现错误,它都会引发一个 ValidationError
。
注意
验证代码不应自身引发 ValidationError
,而应引发 ValueError
或 AssertionError
(或其子类),这些将被捕获并用于填充 ValidationError
。
无论发现多少错误,都会抛出一个异常,其中 ValidationError
将包含有关所有错误以及它们如何发生的信息。
你可以通过多种方式访问这些错误:
方法
描述
e.errors()
返回输入数据中发现的错误列表。
e.error_count()
返回 errors
中发现的错误数量。
e.json()
返回 errors
的 JSON 表示形式。
str(e)
返回错误的人类可读表示形式。
每个错误对象都包含:
财产
描述
ctx
一个可选对象,其中包含呈现错误消息所需的值。
input
验证提供的输入。
loc
错误的位置列表。
msg
错误的人类可读解释。
type
错误类型的计算机可读标识符。
url
关于错误的进一步信息的 URL。
loc
列表中的第一项将是发生错误的字段,如果该字段是子模型,则会有后续项来指示错误的嵌套位置。
作为一个示范:
from typing import List
from pydantic import BaseModel, ValidationError, conint
class Location(BaseModel):
lat: float = 0.1
lng: float = 10.1
class Model(BaseModel):
is_required: float
gt_int: conint(gt=42)
list_of_ints: List[int] = None
a_float: float = None
recursive_model: Location = None
data = dict(
list_of_ints=['1', 2, 'bad'],
a_float='not a float',
recursive_model={'lat': 4.2, 'lng': 'New York'},
gt_int=21,
)
try:
Model(**data)
except ValidationError as e:
print(e)
"""
5 validation errors for Model
is_required
Field required [type=missing, input_value={'list_of_ints': ['1', 2,...ew York'}, 'gt_int': 21}, input_type=dict]
gt_int
Input should be greater than 42 [type=greater_than, input_value=21, input_type=int]
list_of_ints.2
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='bad', input_type=str]
a_float
Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='not a float', input_type=str]
recursive_model.lng
Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='New York', input_type=str]
"""
try:
Model(**data)
except ValidationError as e:
print(e.errors())
"""
[
{
'type': 'missing',
'loc': ('is_required',),
'msg': 'Field required',
'input': {
'list_of_ints': ['1', 2, 'bad'],
'a_float': 'not a float',
'recursive_model': {'lat': 4.2, 'lng': 'New York'},
'gt_int': 21,
},
'url': 'https://pydantic.com.cn/errors/validation_errors#missing',
},
{
'type': 'greater_than',
'loc': ('gt_int',),
'msg': 'Input should be greater than 42',
'input': 21,
'ctx': {'gt': 42},
'url': 'https://pydantic.com.cn/errors/validation_errors#greater_than',
},
{
'type': 'int_parsing',
'loc': ('list_of_ints', 2),
'msg': 'Input should be a valid integer, unable to parse string as an integer',
'input': 'bad',
'url': 'https://pydantic.com.cn/errors/validation_errors#int_parsing',
},
{
'type': 'float_parsing',
'loc': ('a_float',),
'msg': 'Input should be a valid number, unable to parse string as a number',
'input': 'not a float',
'url': 'https://pydantic.com.cn/errors/validation_errors#float_parsing',
},
{
'type': 'float_parsing',
'loc': ('recursive_model', 'lng'),
'msg': 'Input should be a valid number, unable to parse string as a number',
'input': 'New York',
'url': 'https://pydantic.com.cn/errors/validation_errors#float_parsing',
},
]
"""
自定义错误¶
在自定义数据类型或验证器中,应使用 ValueError
或 AssertionError
来引发错误。
有关 @validator
修饰符使用的更多详细信息,请参见验证器。
from pydantic import BaseModel, ValidationError, field_validator
class Model(BaseModel):
foo: str
@field_validator('foo')
def value_must_equal_bar(cls, v):
if v != 'bar':
raise ValueError('value must be "bar"')
return v
try:
Model(foo='ber')
except ValidationError as e:
print(e)
"""
1 validation error for Model
foo
Value error, value must be "bar" [type=value_error, input_value='ber', input_type=str]
"""
print(e.errors())
"""
[
{
'type': 'value_error',
'loc': ('foo',),
'msg': 'Value error, value must be "bar"',
'input': 'ber',
'ctx': {'error': ValueError('value must be "bar"')},
'url': 'https://pydantic.com.cn/errors/validation_errors#value_error',
}
]
"""
你也可以使用 PydanticCustomError
,来完全控制错误结构:
from pydantic_core import PydanticCustomError
from pydantic import BaseModel, ValidationError, field_validator
class Model(BaseModel):
foo: str
@field_validator('foo')
def value_must_equal_bar(cls, v):
if v != 'bar':
raise PydanticCustomError(
'not_a_bar',
'value is not "bar", got "{wrong_value}"',
dict(wrong_value=v),
)
return v
try:
Model(foo='ber')
except ValidationError as e:
print(e)
"""
1 validation error for Model
foo
value is not "bar", got "ber" [type=not_a_bar, input_value='ber', input_type=str]
"""
错误信息¶
Pydantic 试图为验证和使用错误提供有用的默认错误消息。
我们在以下部分提供了默认错误代码的文档:
自定义错误消息¶
你可以通过创建自定义错误处理程序来自定义错误消息。
from typing import Dict, List
from pydantic_core import ErrorDetails
from pydantic import BaseModel, HttpUrl, ValidationError
CUSTOM_MESSAGES = {
'int_parsing': 'This is not an integer! 🤦',
'url_scheme': 'Hey, use the right URL scheme! I wanted {expected_schemes}.',
}
def convert_errors(
e: ValidationError, custom_messages: Dict[str, str]
) -> List[ErrorDetails]:
new_errors: List[ErrorDetails] = []
for error in e.errors():
custom_message = custom_messages.get(error['type'])
if custom_message:
ctx = error.get('ctx')
error['msg'] = (
custom_message.format(**ctx) if ctx else custom_message
)
new_errors.append(error)
return new_errors
class Model(BaseModel):
a: int
b: HttpUrl
try:
Model(a='wrong', b='ftp://example.com')
except ValidationError as e:
errors = convert_errors(e, CUSTOM_MESSAGES)
print(errors)
"""
[
{
'type': 'int_parsing',
'loc': ('a',),
'msg': 'This is not an integer! 🤦',
'input': 'wrong',
'url': 'https://pydantic.com.cn/errors/validation_errors#int_parsing',
},
{
'type': 'url_scheme',
'loc': ('b',),
'msg': "Hey, use the right URL scheme! I wanted 'http' or 'https'.",
'input': 'ftp://example.com',
'ctx': {'expected_schemes': "'http' or 'https'"},
'url': 'https://pydantic.com.cn/errors/validation_errors#url_scheme',
},
]
"""
常见的使用场景是翻译错误消息。例如,在上例中,我们可以通过用翻译字典替换 CUSTOM_MESSAGES
字典来翻译错误消息。
另一个例子是自定义错误的 'loc'
值的表示方式。
from typing import Any, Dict, List, Tuple, Union
from pydantic import BaseModel, ValidationError
def loc_to_dot_sep(loc: Tuple[Union[str, int], ...]) -> str:
path = ''
for i, x in enumerate(loc):
if isinstance(x, str):
if i > 0:
path += '.'
path += x
elif isinstance(x, int):
path += f'[{x}]'
else:
raise TypeError('Unexpected type')
return path
def convert_errors(e: ValidationError) -> List[Dict[str, Any]]:
new_errors: List[Dict[str, Any]] = e.errors()
for error in new_errors:
error['loc'] = loc_to_dot_sep(error['loc'])
return new_errors
class TestNestedModel(BaseModel):
key: str
value: str
class TestModel(BaseModel):
items: List[TestNestedModel]
data = {'items': [{'key': 'foo', 'value': 'bar'}, {'key': 'baz'}]}
try:
TestModel.model_validate(data)
except ValidationError as e:
print(e.errors()) # (1)!
"""
[
{
'type': 'missing',
'loc': ('items', 1, 'value'),
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://pydantic.com.cn/errors/validation_errors#missing',
}
]
"""
pretty_errors = convert_errors(e)
print(pretty_errors) # (2)!
"""
[
{
'type': 'missing',
'loc': 'items[1].value',
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://pydantic.com.cn/errors/validation_errors#missing',
}
]
"""
-
默认情况下,
e.errors()
会生成一个包含loc
值的错误列表,这些值采用元组的形式。 -
通过我们自定义的
loc_to_dot_sep
函数,我们修改了loc
表示形式。
本文总阅读量次