Pydantic声明类型信息的库

pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid.

Define how data should be in pure, canonical python; validate it with pydantic.

---

pydantic在运行时强制执行类型提示,并在数据无效时提供用户友好的错误。

定义数据应该如何在纯粹的、规范的 python 中;用pydantic验证它。

注意:pydantic主要是一个解析库,而不是验证库。验证是达到目的的一种手段:建立一个符合所提供的类型和约束的模型。

换句话说,pydantic保证输出模型的类型和约束,而不是输入数据。

 

from typing import Optional, List
from pydantic import BaseModel
from datetime import datetime


class User(BaseModel):
    id: int
    name = 'fanjiexiong'   # 提供的默认值推断为字符串;因为它有一个默认值,所以它不是必需的。
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


ex_data = {
    'id': '123',  #这里是字符串, User是int型请注意
    'signup_ts': '2022-01-26 11:26',
    'friends': [1, 3, '2']
}
use = User(**ex_data)
print(use.id)  #这里能打印出来
print(type(use.id))  #是int型,就是因为使用了pydantic会自动帮你转换  (如果可能,字符串、字节或浮点数将被强制转换为整数;否则将引发异常。)
print(use.dict())  # 转换成字典




use2 = User(id=2, name='tarzan', friends=['1'])
print(use2.id)
print(type(use2.id))
print(use2.dict())

返回结果:

123
<class 'int'>
{'id': 123, 'signup_ts': datetime.datetime(2022, 1, 26, 11, 26), 'friends': [1, 3, 2], 'name': 'fanjiexiong'}



2
<class 'int'>
{'id': 2, 'signup_ts': None, 'friends': [1], 'name': 'tarzan'}

 

如果验证失败,pydantic 将引发错误并详细说明错误:

from pydantic import ValidationError

try:
    User(signup_ts='broken', friends=[1, 2, 'not number'])
except ValidationError as e:
    print(e.json())

 

 

安装

pip3 install pydantic

基本使用

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name = 'Jane Doe'

User这是一个模型,它有两个字段id整数,name字符串,name不是必需的(它有一个默认值)。name是从默认值推断出来的,因此不需要类型注释(但是请注意当某些字段没有类型注释时有关字段顺序的警告) 

user = User(id='123')

user这是一个实例User。对象的初始化将执行所有解析和验证,如果没有ValidationError引发,您知道生成的模型实例是有效的。

assert user.id == 123

模型的字段可以作为用户对象的普通属性访问。字符串 '123' 已根据字段类型转换为 int

assert user.name == 'Jane Doe'

name初始化用户时未设置,因此它具有默认值

assert user.dict() == dict(user) == {'id': 123, 'name': 'Jane Doe'}

.dict()dict(user)提供字段的字典,但.dict()可以采用许多其他参数。

user.id = 321
assert user.id == 321

此模型是可变的,因此可以更改字段值。

 

实例化的对象具有的方法

具有以下方法和属性:

dict()
返回模型字段和值的字典;
json()
返回一个 JSON 字符串表示dict()
copy()
返回模型的副本(默认为浅拷贝);其实理解成深拷贝也没有问题, 因为List不支持[]语法,只有Tuple支持[],元祖本身就是不可变对象
parse_obj()
如果对象不是字典,则用于将任何对象加载到具有错误处理的模型中的实用程序;
parse_raw()
用于加载多种格式字符串的实用程序;
parse_file()
喜欢parse_raw()但是对于文件路径;
schema()
返回将模型表示为 JSON Schema 的字典;
schema_json()
schema()返回;的 JSON 字符串表示形式 

递归模型:

from typing import List
from pydantic import BaseModel


class Foo(BaseModel):
    count: int
    size: float = None


class Bar(BaseModel):
    apple = 'x'
    banana = 'y'


class Spam(BaseModel):
    foo: Foo
    bars: List[Bar]   # bars参数外面是个列表,列表里面是多个Bar模型每一个都是已通过字典封装的


ex = {
    'foo': {'count': 1},
    "bars": [{
        'apple': 'x1',
        'banana': 'y1'
    }]
}
s = Spam(**ex)
print(s.dict())

 

ORM 模式

Pydantic 模型可以从任意类实例创建以支持映射到 ORM 对象的模型。

  1. Config属性orm_mode必须设置True为。
  2. from_orm必须使用特殊构造函数来创建模型实例。

此处的示例使用 SQLAlchemy,但相同的方法应该适用于任何 ORM。  这里还没有看出来什么时候使用他

from typing import List
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, constr

Base = declarative_base()


class CompanyOrm(Base):
    __tablename__ = 'companies'
    id = Column(Integer, primary_key=True, nullable=False)
    public_key = Column(String(20), index=True, nullable=False, unique=True)
    name = Column(String(63), unique=True)
    domains = Column(ARRAY(String(255)))


class CompanyModel(BaseModel):
    id: int
    public_key: constr(max_length=20)
    name: constr(max_length=63)
    domains: List[constr(max_length=255)]

    class Config:
        orm_mode = True


co_orm = CompanyOrm(
    id=123,
    public_key='foobar',
    name='Testing',
    domains=['example.com', 'foobar.com'],
)
print(co_orm)
#> <models_orm_mode.CompanyOrm object at 0x7f0bdac44850>
co_model = CompanyModel.from_orm(co_orm)
print(co_model)
#> id=123 public_key='foobar' name='Testing' domains=['example.com',
#> 'foobar.com']
posted @ 2022-01-26 11:42  Tarzen  阅读(295)  评论(0编辑  收藏  举报