嘘~ 正在从服务器偷取页面 . . .

Pydantic


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 将只允许 applepumpkin
此字段类型的一个优点是,它可用于检查与一个或多个特定值的相等性,而无需声明自定义验证程序:
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() 返回 schemajson 字符串表示形式

  • 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
  • 上面的代码中 DynamicFoobarModelStaticFoobarModel 是一样的 一个是代码执行时创建 一个是 直接在代码层实现
  • __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 是可选 虽然 它没有默认值
  • 但是 bc... 修饰 指明了是一个必填字段

动态默认值

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 一个无参函数 当对象需要默认值时 将调用这个函数 禁止同时设置 defaultdefault_factory
alias 字段的公共名称
gt 大于
ge 大于等于
lt 小于
le 小于等于
regex 用正则表达式验证字符串
repr 默认为True 。如果为 False,则该字段应从对象表示中隐藏(允许不传这个字段)
增加加下划线为请求中都隐藏

文章作者: 林木木
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 林木木 !
评论
  目录