pydantic
pip install pydantic[email,dotenv]
使用 python 类型注释进行数据验证和设置管理。
pydantic 在运行时强制执行类型提示,并在数据无效时提供用户友好的错误。
定义数据在纯规范的 python 中应该如何;用pydantic验证它。
**上面是官方翻译 我是觉得这种类型验证 对于
Python
这类弱语言很好用 **
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: Optional[datetime] = None
friends: List[int] = []
external_data = {
'id': '123',
'signup_ts': '2019-06-01 12:22',
'friends': [1, 2, '3'],
}
user = User(**external_data)
- 上面给
User
类传递了一个dict
并进行解包 那么内部的每个对应对象 就会被一一赋值 - 虽然 传入的
id
为字符串的123
但是上面指定了int
就会被自动转换为数字的123
字段类型
类型 | 解释 |
---|---|
None | 空类型 |
bool | bool 形 |
int | 整形 |
float | 浮点型 |
str | 字符串 |
bytes | bytes 数组 |
list | 列表 |
tuple | 元组 |
dict | 字典 |
frozenset | 冻结集合 不允许再添加和删除元素 |
deque | 一个与队列类似的 双端有序集合 可以从两边删除 添加元素 |
datetime.date | 时间 日期 类型 |
typing.Any | 允许任何值 包括 None 因此是可选的 |
typing.Annotated | 允许使用任意元数据包装另一种类型 |
typing.Union | 允许一个属性 接收不同的类型 相比于 Optional 更加快捷 |
typing.Optional | 可选的一个字段类型 |
FilePath | 文件路径 并且 文件必须存在 |
DirectoryPath | 必须 存在并且必须是一个目录 |
PastDate | 时间对象 必须是已经过去的时间 |
FutureDate | 时间对象 必须是未来的时间 |
EmailStr | 邮箱验证器 输出的是简单字符串 |
Color | Css 颜色类型 |
Json | 特殊的包装器类型 在解析之前加载 JSON |
PaymentCardNumber | 银行卡号类型 |
AnyUrl | 任何网址类型 |
FileUrl | 文件路径网址 |
HttpUrl | 更严格的网址类型 |
PostgresDsn | DNS 样式的 URL |
RedisDsn | Redis 样式的 DNF 网址类型 |
UUID1-UUID5 | UUID 随机值 |
SecretStr | 可以使用 和 数据类型来存储不希望在日志记录或回溯中可见的敏感信息。 |
Iterable | 可迭代类型 |
Enum | 枚举类型 |
Callable | 可调用对象 Callable[[int], int] 前面 [] 指定参数 |
c: Type[Foo] | 指明 c 传入的类型 必须是 Foo 这个类本身 实例也不行 Type 则表示任何类 |
flavor: Literal[‘apple’, ‘pumpkin’] | 文本类型 flavor 将只允许 apple 与 pumpkin 此字段类型的一个优点是,它可用于检查与一个或多个特定值的相等性,而无需声明自定义验证程序: |
IPvAnyAddress | ip 地址 |
基本用法
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'Jane Doe'
- 很明了 定义一个类 需要继承
BaseModel
- 其中
id
为必须name
非必须 - 其中
user
实例还有以下方法
dict()
返回模型字段和值的字典json()
返回 JSON 字符串表示形式copy()
返回模型的副本(默认为浅副本)parse_obj()
一个实用程序,用于将任何对象加载到模型中,如果对象不是字典,则进行错误处理- 上面的实例化可以改写为
User.parse_obj(external_data)
- 上面的实例化可以改写为
parse_raw()
另外一种解析方式 可以将'{"id": 123, "name": "James"}'
- 解析为
id=123 signup_ts=None friends=[] name='James'
- 解析为
parse_file()
解析文件路径from_orm()
将任意类 加载到模型中 搭配sqlalchemy
使用item_list = PersonSqlSession.query(SqlPerson).all()
new_item_list = [AddPersonModel.from_orm(item) for item in item_list]
schema()
返回一个字典,将模型表示为 JSON 架构schema_json()
返回schema
的json
字符串表示形式User.construct()
用于在不运行验证的情况下创建模型的类方法- 当你相信数据的来源 并且希望高效的创建的时候 可以使用 不推荐
__fields_set__
初始化模型实例时设置的字段名称集__fields__
模型字段的字典__config__
模型的配置类- 后面会学到的一个 内部类
Config
用于配置规则
- 后面会学到的一个 内部类
- 每当pydantic在它正在验证的数据中发现错误时,它就会引发。
ValidationError
- 可以通过以下属性 访问 异常信息
e.errors()
方法将返回在输入数据中发现的错误列表。e.json()
方法将返回 的 JSON 表示形式。str(e)
方法将返回错误的人类可读表示形式。type
错误类型的计算机可读标识符。msg
人类可读的错误解释。ctx
一个可选对象,其中包含呈现错误消息所需的值。
class Model(BaseModel):
foo: str
@validator('foo')
def value_must_equal_bar(cls, v):
if v != 'bar':
raise ValueError('value must be "bar"')
return v
- 验证数据 以及 自定义错误信息
动态创建模型
from pydantic import BaseModel, create_model
DynamicFoobarModel = create_model('DynamicFoobarModel', foo=(str, ...), bar=123)
class StaticFoobarModel(BaseModel):
foo: str
bar: int = 123
- 上面的代码中
DynamicFoobarModel
和StaticFoobarModel
是一样的 一个是代码执行时创建 一个是 直接在代码层实现 __base__=FooModel,
传入create_model
可以指定父类
不可变性
- 可以通过 将模型配置为不可变。设置此值后,尝试更改实例属性的值将引发错误。
class FooBarModel(BaseModel):
a: str
b: dict
class Config:
allow_mutation = False
抽象类
Pydantic模型可以与Python的抽象基类ABC一起使用。
import abc
from pydantic import BaseModel
class FooBarModel(BaseModel, abc.ABC):
a: str
b: int
@abc.abstractmethod
def my_abstract_method(self):
pass
必填字段
class Model(BaseModel):
a: int
b: int = ...
c: int = Field(...)
- 以上三种形式 都是定义一个必填字段
class Model(BaseModel):
a: Optional[int]
b: Optional[int] = ...
c: Optional[int] = Field(...)
- 以上代码中
a
是可选 虽然 它没有默认值 - 但是
b
与c
被...
修饰 指明了是一个必填字段
动态默认值
from datetime import datetime
from uuid import UUID, uuid4
from pydantic import BaseModel, Field
class Model(BaseModel):
uid: UUID = Field(default_factory=uuid4)
updated: datetime = Field(default_factory=datetime.utcnow)
- 其中 两个属性 都定义了一个默认值 但默认值并不是固定的
私有模型属性
- 如果需要更改或操作模型实例上的内部属性,可以使用 以下命令声明它们
from datetime import datetime
from random import randint
from pydantic import BaseModel, PrivateAttr
class TimeAwareModel(BaseModel):
_processed_at: datetime = PrivateAttr(default_factory=datetime.now)
_secret_value: str = PrivateAttr()
def __init__(self, **data):
super().__init__(**data)
# this could also be done with default_factory
self._secret_value = randint(1, 5)
验证器
class UserModel(BaseModel):
name: str
@validator('name')
def name_must_contain_space(cls, v):
if ' ' not in v:
raise ValueError('must contain a space')
return v.title()
@validator('cube_numbers', 'square_numbers')
def check_sum(cls, v):
if sum(v) > 42:
raise ValueError('sum of numbers greater than 42')
return v
- 一个简单的验证器代码
- 验证器是“类方法”,因此它们收到的第一个参数值是类,而不是 的实例。
- 第二个参数始终是要验证的字段值
- 它可以随心所欲地命名
- 单个验证器可以通过向多个字段名称传递来应用于多个字段
- 也可以通过传递特殊值
*
在所有*字段上调用单个验证器
- 也可以通过传递特殊值
pre
关键字参数将导致在其他验证之前调用验证程序each_item
传递将导致验证器应用于单个值 而不是整个对象[1,2,3]
将只会验证第一个值
- **注意 验证程序应返回解析的值或引发 **
始终验证 ( 另外一种设置默认值的方式 )
- 出于性能原因,默认情况下,如果未提供值,则不会为字段调用验证程序。
- 但是,在某些情况下,始终调用验证器可能是有用的或必需的,例如,设置动态默认值。
class DemoModel(BaseModel):
ts: datetime = None
@validator('ts', pre=True, always=True)
def set_ts_now(cls, v):
return v or datetime.now()
- 默认值虽然 为
None
并且不是必须 但设置了 始终验证always
如果用户未传值的情况下 就会以datetime.now()
为准
重用验证器
- 有时,您需要在多个字段/模型上使用相同的验证器(例如,规范化某些输入数据)。
from pydantic import BaseModel, validator
def normalize(name: str) -> str:
return ' '.join((word.capitalize()) for word in name.split(' '))
class Producer(BaseModel):
name: str
_normalize_name = validator('name', allow_reuse=True)(normalize)
class Consumer(BaseModel):
name: str
_normalize_name = validator('name', allow_reuse=True)(normalize)
根验证器 ( 全局验证 )
- 可以对一个类中 所有的类型进行验证
from pydantic import BaseModel, ValidationError, root_validator
class UserModel(BaseModel):
username: str
password1: str
password2: str
@root_validator(pre=True)
def check_card_number_omitted(cls, values):
assert 'card_number' not in values, 'card_number should not be included'
return values
@root_validator
def check_passwords_match(cls, values):
pw1, pw2 = values.get('password1'), values.get('password2')
if pw1 is not None and pw2 is not None and pw1 != pw2:
raise ValueError('passwords do not match')
return values
模型配置
pydantic
的行为可以通过模型或*pydantic* dataclass
上的类来控制.- 在类的内部 再写一个内部类来进行配置
class Model(BaseModel):
v: str
class Config:
max_anystr_length = 10
key | value |
---|---|
title |
生成的 JSON 架构的标题 |
anystr_strip_whitespace |
是否去除 str 和字节类型的前导和尾随空格(默认值:False ) |
anystr_lower |
是否使 str 和字节类型的所有字符都小写(默认值:False ) |
min_anystr_length |
str & byte 类型的最小长度(默认值:0 ) |
max_anystr_length |
str & byte 类型的最大长度(默认值:None ) |
validate_all |
是否验证字段默认值(默认值:False ) |
extra |
在模型初始化期间是忽略、允许还是禁止额外的属性。 |
allow_mutation |
模型是否为仿不可变的,即是否允许(默认值:__setattr__ True ) True 表示可改变 |
use_enum_values |
是否使用枚举的属性(而不是原始枚举)填充模型。 |
validate_assignment |
是否对属性的分配执行验证(默认值:False ) |
error_msg_templates |
用于覆盖默认错误消息模板。以 dict 的方式传入 key错误 和 value异常信息 |
orm_mode |
是否允许使用 ORM 模式 |
字段
class Model(BaseModel):
foo = Field()
字段 | 解释 |
---|---|
… | 必填字段 |
default | 默认值 |
default_factory | 一个无参函数 当对象需要默认值时 将调用这个函数 禁止同时设置 default 和 default_factory |
alias | 字段的公共名称 |
gt | 大于 |
ge | 大于等于 |
lt | 小于 |
le | 小于等于 |
regex | 用正则表达式验证字符串 |
repr | 默认为True 。如果为 False,则该字段应从对象表示中隐藏(允许不传这个字段)增加加下划线为请求中都隐藏 |