Pydantic官方文档
Pydantic官方文档
email-validator。
Literal,需要安装 typing-extensions。Settings 的 dotenv 文件支持需要安装 python-dotenv。要将这些与 pydantic 一起安装,可以使用如下方式:
pip install pydantic[email]
# or
pip install pydantic[typing_extensions]
# or
pip install pydantic[dotenv]
# or just
pip install pydantic[email,typing_extensions,dotenv]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
当然,你可以使用 pip install email-validator 和/或 pip install typing_extensions 手动安装这些依赖。
如果想从存储库直接安装 pydantic,可以使用:
pip install git+git://github.com/samuelcolvin/pydantic@master#egg=pydantic
# or with extras
pip install git+git://github.com/samuelcolvin/pydantic@master#egg=pydantic[email,typing_extensions]
- 1
- 2
- 3
util.py) 处理任意类,该类试图为任何类提供一个类似于字典的接口。可以通过将 GetterDict 的自定义子类设置为 Config.getter_dict 的值来覆盖默认行为(参考 [模型配置](# 3.4 模型配置))。
您还可以使用带有 pre=True 的 root_validators 定制类验证。在这种情况下,validator 函数将被传递一个可以复制和修改的GetterDict 实例。
pickle 的官方文档,“pickle模块对于错误或恶意构造的数据是不安全的。切勿从不可信或未经身份验证的来源获取数据。”
注意
由于它可能导致任意代码的执行,因此作为一种安全措施,您需要显式地将 allow_pickle 传递给解析函数,以便加载pickle数据。
samuelcolvin/pydantic#1047。
注意
由于它可能导致任意代码的执行,因此作为一种安全措施,您需要显式地将 allow_pickle 传递给解析函数,以便加载pickle数据。
字段可以由 ( 形式的元组定义,也可以仅由默认值定义。__config__ 和 __base__ 这两个特殊的关键字参数可以用来定制新模型。这包括使用额外的字段拓展基本模型。
from pydantic import BaseModel, create_model
class FooModel(BaseModel):
foo: str
bar: int = 123
BarModel = create_model(
'BarModel',
apple='russet',
banana='yellow',
__base__=FooModel,
)
print(BarModel)
#>
print(BarModel.__fields__.keys())
#> dict_keys(['foo', 'bar', 'apple', 'banana'])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
也可以通过给 __validators__ 参数传递一个字典来添加验证器:
from pydantic import create_model, ValidationError, validator
def username_alphanumeric(cls, v):
assert v.isalnum(), 'must be alphanumeric'
return v
validators = {
'username_validator':
validator('username')(username_alphanumeric)
}
UserModel = create_model(
'UserModel',
username=(str, ...),
__validators__=validators
)
user = UserModel(username='scolvin')
print(user)
#> username='scolvin'
try:
UserModel(username='scolvi%n')
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
username
must be alphanumeric (type=assertion_error)
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
mypy 中不能很好的工作,在v1.0中大多数情况下都应该避免使用。
#866或者创建一个新问题。
示例用法:
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)
m1 = Model()
m2 = Model()
print(f'{m1.uid} != {m2.uid}')
#> 27ce808f-9293-47ac-860e-aebe5d6ffac7 != a583211f-b357-4b92-9632-cd1b3bbd2e1b
print(f'{m1.updated} != {m2.updated}')
#> 2020-10-28 20:03:32.840916 != 2020-10-28 20:03:32.840934
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
其中 Field 引用 [字段函数](# 3.5.1 字段定制)。
警告
default_factory希望设置字段类型,此外,如果您希望使用validate_all验证默认值,则pydantic需要调用default_factory,这可能会导致副作用!
这里可以看到关于这个问题的更长的讨论。
#1055被解决后被修复。
datetime 了类型:
datetime 字段可以是:
datetime:存在 datetime 对象时
int 或 float:假定为 Unix 时间时。例如,自1970年1月1日以来的秒数 (如果 >= -2e10 或 <= 2e10) 或毫秒数 (如果 < -2e10 或 > 2e10)。
str:下面的格式可用时:
YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
- 作为字符串的
int 或 floats (假定为Unix time)
date 字段可以是:
date:存在 date 对象时
int 或float: 参见 datetime
str:下面的格式可用时:
YYYY-MM-DD
int 或 float 参见 datetime
time 字段可以是:
time:存在 time 对象时
str:下面的格式可用时:
HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
timedelta 字段可以是:
timedelta:存在 timedelta 对象时
int 或 float:假定为"秒"
str:下面的格式可用时:
[-][DD ][HH:MM]SS[.ffffff]
[±]P[DD]DT[HH]H[MM]M[SS]S (ISO 8601 的 timedelta 格式)
from datetime import date, datetime, time, timedelta
from pydantic import BaseModel
class Model(BaseModel):
d: date = None
dt: datetime = None
t: time = None
td: timedelta = None
m = Model(
d=1966280412345.6789,
dt='2032-04-23T10:20:30.400+02:30',
t=time(4, 8, 16),
td='P3DT12H30M5S',
)
print(m.dict())
"""
{
'd': datetime.date(2032, 4, 22),
'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000,
tzinfo=datetime.timezone(datetime.timedelta(seconds=9000))),
't': datetime.time(4, 8, 16),
'td': datetime.timedelta(days=3, seconds=45005),
}
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
typing-extensions。
datetime 了类型:
datetime 字段可以是:
datetime:存在 datetime 对象时
int 或 float:假定为 Unix 时间时。例如,自1970年1月1日以来的秒数 (如果 >= -2e10 或 <= 2e10) 或毫秒数 (如果 < -2e10 或 > 2e10)。
str:下面的格式可用时:
YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
- 作为字符串的
int 或 floats (假定为Unix time)
date 字段可以是:
date:存在 date 对象时
int 或float: 参见 datetime
str:下面的格式可用时:
YYYY-MM-DD
int 或 float 参见 datetime
time 字段可以是:
time:存在 time 对象时
str:下面的格式可用时:
HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
timedelta 字段可以是:
timedelta:存在 timedelta 对象时
int 或 float:假定为"秒"
str:下面的格式可用时:
[-][DD ][HH:MM]SS[.ffffff]
[±]P[DD]DT[HH]H[MM]M[SS]S (ISO 8601 的 timedelta 格式)
from datetime import date, datetime, time, timedelta
from pydantic import BaseModel
class Model(BaseModel):
d: date = None
dt: datetime = None
t: time = None
td: timedelta = None
m = Model(
d=1966280412345.6789,
dt='2032-04-23T10:20:30.400+02:30',
t=time(4, 8, 16),
td='P3DT12H30M5S',
)
print(m.dict())
"""
{
'd': datetime.date(2032, 4, 22),
'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000,
tzinfo=datetime.timezone(datetime.timedelta(seconds=9000))),
't': datetime.time(4, 8, 16),
'td': datetime.timedelta(days=3, seconds=45005),
}
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
typing-extensions。
datetime 字段可以是:
datetime:存在datetime对象时int或float:假定为 Unix 时间时。例如,自1970年1月1日以来的秒数 (如果 >=-2e10或 <=2e10) 或毫秒数 (如果 <-2e10或 >2e10)。str:下面的格式可用时:YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]- 作为字符串的
int或floats (假定为Unix time)
date 字段可以是:
date:存在date对象时int或float: 参见datetimestr:下面的格式可用时:YYYY-MM-DDint或float参见datetime
time 字段可以是:
time:存在time对象时str:下面的格式可用时:HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
timedelta 字段可以是:
timedelta:存在timedelta对象时int或float:假定为"秒"str:下面的格式可用时:[-][DD ][HH:MM]SS[.ffffff][±]P[DD]DT[HH]H[MM]M[SS]S(ISO 8601 的 timedelta 格式)
from datetime import date, datetime, time, timedelta
from pydantic import BaseModel
class Model(BaseModel):
d: date = None
dt: datetime = None
t: time = None
td: timedelta = None
m = Model(
d=1966280412345.6789,
dt='2032-04-23T10:20:30.400+02:30',
t=time(4, 8, 16),
td='P3DT12H30M5S',
)
print(m.dict())
"""
{
'd': datetime.date(2032, 4, 22),
'dt': datetime.datetime(2032, 4, 23, 10, 20, 30, 400000,
tzinfo=datetime.timezone(datetime.timedelta(seconds=9000))),
't': datetime.time(4, 8, 16),
'td': datetime.timedelta(days=3, seconds=45005),
}
"""pydantic支持使用 typing.Literal (或者在 Python3.8之前,使用 typing_extensions.Literal) 作为一种轻量级的方式来指定一个字段只能接受特定的字面量:
from typing import Literal
from pydantic import BaseModel, ValidationError
class Pie(BaseModel):
flavor: Literal['apple', 'pumpkin']
Pie(flavor='apple')
Pie(flavor='pumpkin')
try:
Pie(flavor='cherry')
except ValidationError as e:
print(str(e))
"""
1 validation error for Pie
flavor
unexpected value; permitted: 'apple', 'pumpkin'
(type=value_error.const; given=cherry; permitted=('apple', 'pumpkin'))
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
这个字段类型的一个好处是,它可以用来检查一个或多个特定值是否相等,而不需要声明自定义验证器:
from typing import ClassVar, List, Union
from typing import Literal
from pydantic import BaseModel, ValidationError
class Cake(BaseModel):
kind: Literal['cake']
required_utensils: ClassVar[List[str]] = ['fork', 'knife']
class IceCream(BaseModel):
kind: Literal['icecream']
required_utensils: ClassVar[List[str]] = ['spoon']
class Meal(BaseModel):
dessert: Union[Cake, IceCream]
print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Cake
print(type(Meal(dessert={'kind': 'icecream'}).dessert).__name__)
#> IceCream
try:
Meal(dessert={'kind': 'pie'})
except ValidationError as e:
print(str(e))
"""
2 validation errors for Meal
dessert -> kind
unexpected value; permitted: 'cake' (type=value_error.const; given=pie;
permitted=('cake',))
dessert -> kind
unexpected value; permitted: 'icecream' (type=value_error.const;
given=pie; permitted=('icecream',))
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
在带注解的 Union 中使用适当的排序,你可以使用它来解析特定的降序类型(types of descreasing):
from typing import Optional, Union
from typing import Literal
from pydantic import BaseModel
class Dessert(BaseModel):
kind: str
class Pie(Dessert):
kind: Literal['pie']
flavor: Optional[str]
class ApplePie(Pie):
flavor: Literal['apple']
class PumpkinPie(Pie):
flavor: Literal['pumpkin']
class Meal(BaseModel):
dessert: Union[ApplePie, PumpkinPie, Pie, Dessert]
print(type(Meal(dessert={'kind': 'pie', 'flavor': 'apple'}).dessert).__name__)
#> ApplePie
print(type(Meal(dessert={'kind': 'pie', 'flavor': 'pumpkin'}).dessert).__name__)
#> PumpkinPie
print(type(Meal(dessert={'kind': 'pie'}).dessert).__name__)
#> Pie
print(type(Meal(dessert={'kind': 'cake'}).dessert).__name__)
#> Dessert
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
email-validator;输入字符串必须是有效的 email地址,输出是一个简单字符串。
NameEmail
需要安装 email-validator;输入字符串必须是有效的 email地址或是 Fred Bloggs 这样的格式,输出是一个 NameEmail 对象,该对象有两个属性:name 和 email。对于 Fred Bloggs ,名称将会是 Fred Bloggs。对于 fred.bloggs@example.com,名称将会是 fred.bloggs。
PyObject
需要一个可调用对象或一个包含 . 的表示导入路径的字符串。如果提供的是一个字符串,则从该字符串所表示的导入路径加载最后一个 . 右边的子串所表示的可导入Python 对象。 例如,如果提供了 'math.cos',则结果字段值将为函数 cos。如果提供了 pydantic.dataclasses.dataclass,则结果字段值将为 dataclass。
Color
用于解析 HTML 和 CSS 颜色。参见 [Color类型](3.2.3.2 Color 类型)。
Json
一个特殊的类型包装器,在解析之前加载JSON; 参见 [JSON类型](# 3.2.3.4 Json 类型)。
PaymentCardNumber
对支付卡进行解析和验证;参见 [PaymentCardNumber 类型](3.2.3.5 PaymentCardNumber)。
AnyUrl
任意 URL。参见 [URL](# 3.2.3.1 URL)
AnyHttpUrl
一个 HTTP URL。参见 [URL](# 3.2.3.1 URL)
HttpUrl
更严格的HTTP URL。参见 [URL](# 3.2.3.1 URL)。
PostgresDsn
Postgres DSN 样式的 URL。参见 [URL](# 3.2.3.1 URL)。
RedisDsn
Redis DSN 样式的 URL。参见 [URL](# 3.2.3.1 URL)。
stricturl
用于任意URL约束的类型方法。参见 [URL](# 3.2.3.1 URL)。
UUID1
需要类型1的有效UUID。参见[上面](# 3.2.1 标准库类型)的UUID。
UUID3
需要类型3的有效UUID。参见[上面](# 3.2.1 标准库类型)的UUID。
UUID4
需要类型4的有效UUID。参见[上面](# 3.2.1 标准库类型)的UUID。
UUID5
需要类型5的有效UUID。参见[上面](# 3.2.1 标准库类型)的UUID。
SecretBytes
值部分(partially)保密的字节。参见 [Secret](# 3.2.3.3 Secret 类型)。
SecretStr
值部分(partially)保密的字符串。参见 [Secret](# 3.2.3.3 Secret 类型)。
IPvAnyAddress
允许一个 IPv4Address 或一个 IPv6Address。
IPvAnyInterface
允许一个 IPv4Interface 或一个 IPv6Interface。
IPvAnyNetwork
允许一个 IPv4Network 或一个 IPv6Network。
NegativeFloat
允许负的浮点数; 使用标准的 float 解析,然后检查该值是否小于0; 请参阅 [约束类型](3.2.4 约束类型)。
NegativeInt
允许负的整数; 使用标准的 int 解析,然后检查该值是否小于0; 请参阅 [约束类型](3.2.4 约束类型)。
PositiveFloat
允许正的浮点数; 使用标准的 float 解析,然后检查该值是否大于0; 请参阅 [约束类型](3.2.4 约束类型)。
PosiviteInt
允许正的整数; 使用标准的 int 解析,然后检查该值是否大于0; 请参阅 [约束类型](3.2.4 约束类型)。
conbytes
用于约束 bytes 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
condecimal
用于约束 Decimal 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
confloat
用于约束 float 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
conint
用于约束 int 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
conlist
用于约束 list 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
conset
用于约束 set 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
constr
用于约束 str 的类型方法。请参阅 [约束类型](3.2.4 约束类型)。
punycode进行编码(请参见本文,以了解其重要性的详细说明):
from pydantic import BaseModel, HttpUrl
class MyModel(BaseModel):
url: HttpUrl
m1 = MyModel(url='http://puny£code.com')
print(m1.url)
#> http://xn--punycode-eja.com
print(m1.url.host_type)
#> int_domain
m2 = MyModel(url='https://www.арр?е.com/')
print(m2.url)
#> https://www.xn--80ak6aa92e.com/
print(m2.url.host_type)
#> int_domain
m3 = MyModel(url='https://www.example.珠宝/')
print(m3.url)
#> https://www.example.xn--pbt977c/
print(m3.url.host_type)
#> int_domain
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
CSS3规范使用 Color 数据类型存储颜色。 可以通过以下方式定义颜色:
- 名称 (例如
"Black"、"azure" )
- 十六进制值 (例如
"0x000","#FFFFFF","7fffd4" )
- RGB/RGBA 元组 (例如
(255, 255, 255),(255, 255, 255, 0.5) )
- RGB/RGBA 字符串 (例如
"rgb(255, 255, 255)","rgba(255, 255, 255, 0.5)" )
- HSL 字符串 (例如
"hsl(270, 60%, 70%)","hsl(270, 60%, 70%, .5)" )
from pydantic import BaseModel, ValidationError
from pydantic.color import Color
c = Color('ff00ff')
print(c.as_named())
#> magenta
print(c.as_hex())
#> #f0f
c2 = Color('green')
print(c2.as_rgb_tuple())
#> (0, 128, 0)
print(c2.original())
#> green
print(repr(Color('hsl(180, 100%, 50%)')))
#> Color('cyan', rgb=(0, 255, 255))
class Model(BaseModel):
color: Color
print(Model(color='purple'))
#> color=Color('purple', rgb=(128, 0, 128))
try:
Model(color='hello')
except ValidationError as e:
print(e)
"""
1 validation error for Model
color
value is not a valid color: string not recognised as a valid color
(type=value_error.color; reason=string not recognised as a
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
from pydantic import BaseModel, HttpUrl
class MyModel(BaseModel):
url: HttpUrl
m1 = MyModel(url='http://puny£code.com')
print(m1.url)
#> http://xn--punycode-eja.com
print(m1.url.host_type)
#> int_domain
m2 = MyModel(url='https://www.арр?е.com/')
print(m2.url)
#> https://www.xn--80ak6aa92e.com/
print(m2.url.host_type)
#> int_domain
m3 = MyModel(url='https://www.example.珠宝/')
print(m3.url)
#> https://www.example.xn--pbt977c/
print(m3.url.host_type)
#> int_domainColor 数据类型存储颜色。 可以通过以下方式定义颜色:
- 名称 (例如
"Black"、"azure") - 十六进制值 (例如
"0x000","#FFFFFF","7fffd4") - RGB/RGBA 元组 (例如
(255, 255, 255),(255, 255, 255, 0.5)) - RGB/RGBA 字符串 (例如
"rgb(255, 255, 255)","rgba(255, 255, 255, 0.5)") - HSL 字符串 (例如
"hsl(270, 60%, 70%)","hsl(270, 60%, 70%, .5)")
from pydantic import BaseModel, ValidationError
from pydantic.color import Color
c = Color('ff00ff')
print(c.as_named())
#> magenta
print(c.as_hex())
#> #f0f
c2 = Color('green')
print(c2.as_rgb_tuple())
#> (0, 128, 0)
print(c2.original())
#> green
print(repr(Color('hsl(180, 100%, 50%)')))
#> Color('cyan', rgb=(0, 255, 255))
class Model(BaseModel):
color: Color
print(Model(color='purple'))
#> color=Color('purple', rgb=(128, 0, 128))
try:
Model(color='hello')
except ValidationError as e:
print(e)
"""
1 validation error for Model
color
value is not a valid color: string not recognised as a valid color
(type=value_error.color; reason=string not recognised as a
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
Color 有下面一些方法:
-
original传递给
Color的原始字符串或元组。 -
as_named返回一个命名的CSS3的颜色;如果设置了Alpha通道或不存在这种颜色,则会失败。如果提供
fallback=True,则回退到as_hex。 -
as_hex返回格式为
#fff或#ffffff的字符串; 如果设置了Alpha通道,则将包含4(或8)个十六进制值,例如#7f33cc26。 -
as_rgb如果设置了Alpha通道,则返回格式为
rgb(或, , ) rgba(的字符串。, , , ) -
as_rgb_tuple以RGB(a) 格式返回3元组或4元组。
alpha关键字参数可用于定义是否应包含alpha通道; 选项:True——始终包含,False——从不包含,None(默认值)——如果设置,则包含。 -
as_hslhsl(格式的字符串。如果设置了 alpha 通道,则为, , ) hsl(。, , , ) -
as_hsl_tuple以HSL(a)格式返回3元组或4元组。
alpha关键字参数可用于定义是否应包含alpha通道; 选项:True——始终包含,False——从不包含,None(默认值)——如果设置,则包含。
Color 的 __str__ 方法返回 self.as_named(fallback=True)。
注意
as_hsl*是指html和世界上大多数地方使用的色相,饱和度和亮度 “HSL”,而不是Python的colorsys中使用的 “HLS”。
支付卡 (例如贷记卡或信用卡)。
from datetime import date
from pydantic import BaseModel
from pydantic.types import PaymentCardBrand, PaymentCardNumber, constr
class Card(BaseModel):
name: constr(strip_whitespace=True, min_length=1)
number: PaymentCardNumber
exp: date
@property
def brand(self) -> PaymentCardBrand:
return self.number.brand
@property
def expired(self) -> bool:
return self.exp < date.today()
card = Card(
name='Georg Wilhelm Friedrich Hegel',
number='4000000000000002',
exp=date(2023, 9, 30),
)
assert card.number.brand == PaymentCardBrand.visa
assert card.number.bin == '400000'
assert card.number.last4 == '0002'
assert card.number.masked == '400000******0002'
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
from datetime import date
from pydantic import BaseModel
from pydantic.types import PaymentCardBrand, PaymentCardNumber, constr
class Card(BaseModel):
name: constr(strip_whitespace=True, min_length=1)
number: PaymentCardNumber
exp: date
@property
def brand(self) -> PaymentCardBrand:
return self.number.brand
@property
def expired(self) -> bool:
return self.exp < date.today()
card = Card(
name='Georg Wilhelm Friedrich Hegel',
number='4000000000000002',
exp=date(2023, 9, 30),
)
assert card.number.brand == PaymentCardBrand.visa
assert card.number.bin == '400000'
assert card.number.last4 == '0002'
assert card.number.masked == '400000******0002'基于BIN,PaymentCardBrand 可以是以下之一:
PaymentCardBrand.amexPaymentCardBrand.mastercardPaymentCardBrand.visaPaymentCardBrand.other
实际验证验证卡号为:
- 仅含数字的字符串
- luhn 有效
- 如果是 Amex、Mastercard 或 Visa,基于 BIN 长度正确;对于所有其他品牌,则为12至19位数字。
泛型类作为字段类型并使用 __get_validators__ 基于"类型参数" (或子类型)执行自定义验证。
如果您要用作子类型的泛型类具有类方法(classmethod) __get_validators__,则无需使用 arbitrary_types_allowed 即可工作。
因为可以声明接收当前 field 的验证器,所以可以提取 sub_fields (从泛型类类型参数中) 并使用它们验证数据。
from pydantic import BaseModel, ValidationError
from pydantic.fields import ModelField
from typing import TypeVar, Generic
AgedType = TypeVar('AgedType')
QualityType = TypeVar('QualityType')
# This is not a pydantic model, it's an arbitrary generic class
class TastingModel(Generic[AgedType, QualityType]):
def __init__(self, name: str, aged: AgedType, quality: QualityType):
self.name = name
self.aged = aged
self.quality = quality
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
# You don't need to add the "ModelField", but it will help your
# editor give you completion and catch errors
def validate(cls, v, field: ModelField):
if not isinstance(v, cls):
# The value is not even a TastingModel
raise TypeError('Invalid value')
if not field.sub_fields:
# Generic parameters were not provided so we don't try to validate
# them and just return the value as is
return v
aged_f = field.sub_fields[0]
quality_f = field.sub_fields[1]
errors = []
# Here we don't need the validated value, but we want the errors
valid_value, error = aged_f.validate(v.aged, {}, loc='aged')
if error:
errors.append(error)
# Here we don't need the validated value, but we want the errors
valid_value, error = quality_f.validate(v.quality, {}, loc='quality')
if error:
errors.append(error)
if errors:
raise ValidationError(errors, cls)
# Validation passed without errors, return the same instance received
return v
class Model(BaseModel):
# for wine, "aged" is an int with years, "quality" is a float
wine: TastingModel[int, float]
# for cheese, "aged" is a bool, "quality" is a str
cheese: TastingModel[bool, str]
# for thing, "aged" is a Any, "quality" is Any
thing: TastingModel
model = Model(
# This wine was aged for 20 years and has a quality of 85.6
wine=TastingModel(name='Cabernet Sauvignon', aged=20, quality=85.6),
# This cheese is aged (is mature) and has "Good" quality
cheese=TastingModel(name='Gouda', aged=True, quality='Good'),
# This Python thing has aged "Not much" and has a quality "Awesome"
thing=TastingModel(name='Python', aged='Not much', quality='Awesome'),
)
print(model)
"""
wine=
cheese=
thing=
"""
print(model.wine.aged)
#> 20
print(model.wine.quality)
#> 85.6
print(model.cheese.aged)
#> True
print(model.cheese.quality)
#> Good
print(model.thing.aged)
#> Not much
try:
# If the values of the sub-types are invalid, we get an error
Model(
# For wine, aged should be an int with the years, and quality a float
wine=TastingModel(name='Merlot', aged=True, quality='Kinda good'),
# For cheese, aged should be a bool, and quality a str
cheese=TastingModel(name='Gouda', aged='yeah', quality=5),
# For thing, no type parameters are declared, and we skipped validation
# in those cases in the Assessment.validate() function
thing=TastingModel(name='Python', aged='Not much', quality='Awesome'),
)
except ValidationError as e:
print(e)
"""
2 validation errors for Model
wine -> quality
value is not a valid float (type=type_error.float)
cheese -> aged
value could not be parsed to a boolean (type=type_error.bool)
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
优化标志 的 Python 将会禁用 assert 语句,导致验证器停止工作。
当验证器依赖于其他值时,你应该知道:
- 验证按照字段被定义的顺序完成。例如,在上面的示例中,
password2可以访问password1(和name),但password1不能访问password2。关于字段如何排序的详细信息,请参考 [字段排序](# 3.1.11 字段排序)。 - 如果在其他字段上验证失败 (或那个字段缺失),则它不会被包含在
values中,因此,在示例中使用了if 'password1' in values and ...来进行判断。
“upper camel case”,又称 “pascal case”,例如 CamelCase。如果您希望使用 “lower camel case”,例如 camelCase,那么修改上面的 to_camel 函数应该很简单。
#1178和下面的优先顺序。
在一个字段的别名可能被定义在多个地方的情况下,选择的值按如下规则确定(按优先级降序):
- 在模型上直接通过
Field(..., alias=设置。) - 在模型上的
Config.fields中定义。 - 在父模型上通过
Field(..., alias=。) - 在父模型上的
Config.fields中定义。 - 由
alias_generator生成,无论它是在模型上还是在父模型上。
注意
这意味着在子模型上定义的
alias_generator不优先于在父模型的字段上定义的别名。
示例:
from pydantic import BaseModel, Field
class Voice(BaseModel):
name: str = Field(None, alias='ActorName')
language_code: str = None
mood: str = None
class Character(Voice):
act: int = 1
class Config:
fields = {'language_code': 'lang'}
@classmethod
def alias_generator(cls, string: str) -> str:
# this is the same as `alias_generator = to_camel` above
return ''.join(word.capitalize() for word in string.split('_'))
print(Character.schema(by_alias=True))
"""
{
'title': 'Character',
'type': 'object',
'properties': {
'ActorName': {'title': 'Actorname', 'type': 'string'},
'lang': {'title': 'Lang', 'type': 'string'},
'Mood': {'title': 'Mood', 'type': 'string'},
'Act': {'title': 'Act', 'default': 1, 'type': 'integer'},
},
}
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
JSON Schema Core
BaseModel.schema 将会返回模式字典,而 BaseModel.schema_json 将会返回那个字典的 JSON 字符串表示。
根据规范,使用的子模型被添加到 definitions JSON属性并被引用。
所有子模型(及其子模型)的模式都直接放在一个顶级 definitions JSON键中,以便于重用和引用。
经过修改 (通过 Field 类) 的 “子模型”,如自定义标题、描述或默认值,被递归地包括而不是引用。
模型的 description 取自类的文档字符串或 Field 类的 description 参数。
默认情况下使用别名作为键来生成模式,但是可以使用模型属性名而不是调用 MainModel.schema/schema_json(by_alias=False) 来生成模式。
使用 ref_template 关键字参数调用 schema() 或 schema_json() 可以改变 $ref (上面的 #/definitions/FooBar ) 的格式。
ApplePie.schema(ref_template='/schemas/{model}.json#/') ,这里,将会使用 str.format 将 {model} 替换为模型名称。
#1631。
**
任何其他关键字参数 (例如 example) 都将逐字添加到字段的模式中。
[配置类](# 3.4 模型配置) 的 fields 属性可以用来设置上面除 default 之外的所有参数,而不是使用 Field。
JSON Schema Core
format JSON字段用于为更复杂的 string 子类型定义pydantic扩展。从Python/pydantic到JSON模式的字段模式映射请参考原始英文文档。
ujson)。
from datetime import datetime
import ujson
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: datetime = None
class Config:
json_loads = ujson.loads
user = User.parse_raw('{"id": 123,"signup_ts":1234567890,"name":"John Doe"}')
print(user)
#> id=123 signup_ts=datetime.datetime(2009, 2, 13, 23, 31, 30,
#> tzinfo=datetime.timezone.utc) name='John Doe'
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
from datetime import datetime
import ujson
from pydantic import BaseModel
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: datetime = None
class Config:
json_loads = ujson.loads
user = User.parse_raw('{"id": 123,"signup_ts":1234567890,"name":"John Doe"}')
print(user)
#> id=123 signup_ts=datetime.datetime(2009, 2, 13, 23, 31, 30,
#> tzinfo=datetime.timezone.utc) name='John Doe'ujson 通常不能用于转储JSON,因为它不支持对像 datetime 这样的对象进行编码,也不接受 default 回退函数参数。为此,您可以使用另一个库,如 orjson。
from datetime import datetime
import orjson
from pydantic import BaseModel
def orjson_dumps(v, *, default):
# orjson.dumps returns bytes, to match standard json.dumps we need to decode
return orjson.dumps(v, default=default).decode()
class User(BaseModel):
id: int
name = 'John Doe'
signup_ts: datetime = None
class Config:
json_loads = orjson.loads
json_dumps = orjson_dumps
user = User.parse_raw('{"id":123,"signup_ts":1234567890,"name":"John Doe"}')
print(user.json())
#> {"id":123,"signup_ts":"2009-02-13T23:31:30+00:00","name":"John Doe"}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
请注意,orjson 本身就考虑了 datetime 编码,这使得它比 json.dumps 更快。但这意味着您不能总是使用 Config.json_encoders 自定义编码。
dataclasses (在python 3.7中引入)上获得相同的数据验证。
数据类在Python 3.6中使用 dataclasses的backport包 工作。
from datetime import datetime
from pydantic.dataclasses import dataclass
@dataclass
class User:
id: int
name: str = 'John Doe'
signup_ts: datetime = None
user = User(id='42', signup_ts='2032-06-21T12:00')
print(user)
#> User(id=42, name='John Doe', signup_ts=datetime.datetime(2032, 6, 21, 12, 0))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
注意
请记住
pydantic.dataclasses.dataclass是具有验证的dataclasses.dataclass的直接替代。而不是pydantic.BaseModel(在初始化钩子的工作方式上略有不同) 的替代。在某些情况下,子类化BaseModel是更好的选择。有关更多信息和讨论,请参阅 samuelcolvin/pydantic#710。
您可以使用所有标准的pydantic字段类型,并且结果数据类将与标准库 dataclass 装饰器创建的数据类相同。
可以通过 __pydantic_model__ 访问底层模型及其模式。 另外,可以通过 dataclasses.field 指定需要 default_factory 的字段。
import dataclasses
from typing import List
from pydantic.dataclasses import dataclass
@dataclass
class User:
id: int
name: str = 'John Doe'
friends: List[int] = dataclasses.field(default_factory=lambda: [0])
user = User(id='42')
print(user.__pydantic_model__.schema())
"""
{
'title': 'User',
'type': 'object',
'properties': {
'id': {'title': 'Id', 'type': 'integer'},
'name': {
'title': 'Name',
'default': 'John Doe',
'type': 'string',
},
'friends': {
'title': 'Friends',
'default': [0],
'type': 'array',
'items': {'type': 'integer'},
},
},
'required': ['id'],
}
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
pydantic.dataclasses.dataclass 的参数与标准装饰器相同,除了一个额外的关键字参数 config,它与 Config 的含义相同。
警告
v1.2之后,必须安装 Mypy 插件 来对 Pydantic 数据类进行类型检查。
有关结合验证器与数据类的更多信息,请参见 [dataclass验证器](# 3.3.7 Dataclass 验证器)。
#> host='example.com', tld='com', host_type='domain')))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
数据类属性可以由元组、字典或数据类本身的实例填充。
#1205进行评论或者创建一个新问题。
用法示例:
from pydantic import validate_arguments, ValidationError
@validate_arguments
def repeat(s: str, count: int, *, separator: bytes = b'') -> bytes:
b = s.encode()
return separator.join(b for _ in range(count))
a = repeat('hello', 3)
print(a)
#> b'hellohellohello'
b = repeat('x', '4', separator=' ')
print(b)
#> b'x x x x'
try:
c = repeat('hello', 'wrong')
except ValidationError as exc:
print(exc)
"""
1 validation error for Repeat
count
value is not a valid integer (type=type_error.integer)
"""
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
#1205了解更多有关此功能的讨论。
#1098 和带有 “strictness” 标签的其他问题。 如果pydantic将来获得 “strict” 模式,validate_arguments 将具有使用此模式的选项,它甚至可能成为装饰器的默认模式。
python-dotenv。这可以通过 pip install python-dotenv 或 pip install pydantic[dotenv] 来完成。
validate_arguments 将具有使用此模式的选项,它甚至可能成为装饰器的默认模式。
python-dotenv。这可以通过 pip install python-dotenv 或 pip install pydantic[dotenv] 来完成。
Dotenv文件 (通常命名为 .env ) 是一种常见的模式,它可以方便地以独立于平台的方式使用环境变量。
dotenv文件遵循与所有环境变量相同的一般原则,看起来如下:
# ignore comment
ENVIRONMENT="production"
REDIS_ADDRESS=localhost:6379
MEANING_OF_LIFE=42
MY_VAR='Hello world'
- 1
- 2
- 3
- 4
- 5
在 .env 文件中填充变量后,pydantic支持通过两种方式加载该文件:
-
在
BaseSetting类中的Config上设置env_file(和env_file_encoding,如果你不想使用 OS 的默认编码的话)。class Settings(BaseSettings): ... class Config: env_file = '.env' env_file_encoding = 'utf-8'- 1
- 2
- 3
- 4
- 5
- 6
-
使用
_env_file关键字参数 (和_env_file_encoding,如果需要) 实例化BaseSettings派生类:settings = Settings(_env_file='prod.env', _env_file_encoding='utf-8')- 1
无论哪种情况,传递的参数的值都可以是任何有效路径或文件名,可以是绝对路径或相对于当前工作目录的相对路径。pydantic将从那里通过加载变量并对其进行验证来为您处理所有事情。
即使使用dotenv文件,pydantic仍将读取环境变量以及dotenv文件,环境变量将始终优先于从dotenv文件加载的值。
在实例化时(方法2)通过 _env_file 关键字参数传递文件路径将覆盖 Config 类上设置的值(如果有)。如果以上代码段结合使用,则将加载 prod.env,而将忽略 .env。
还可以通过将 None 作为实例化关键字参数传递给 BaseSettings 的派生类的初始化方法来使用关键字参数覆盖来告诉Pydantic根本不加载任何文件 (即使在 Config 类中设置了一个文件),例如 settings = Settings(_env_file = None)。
由于使用 python-dotenv 来解析文件,因此可以使用类似于bash的语义(例如 export) (取决于操作系统和环境) 来允许dotenv文件也与 source 一起使用,请参阅 python-dotenv的文档 以了解更多详细信息。
Docker官方文档。
首先,定义 Settings 类:
class Settings(BaseSettings):
my_secret_data: str
class Config:
secrets_dir = '/run/secrets'
注意
默认情况下,Docker使用
/run/secrets作为目标挂载点。如果你想使用一个不同的位置,改变相应地Config.secrets_dir。
然后,通过 Docker 命令行接口创建机密:
printf "This is a secret" | docker secret create my_secret_data -
最后,运行 Docker 容器内的应用程序并提供新创建的机密:
docker service create --name pydantic-with-secrets --secret my_secret_data pydantic-app:latest
PEP563 所述) “just work”。
from __future__ import annotations
from typing import List
from pydantic import BaseModel
class Model(BaseModel):
a: List[int]
print(Model(a=('1', 2, 3)))
#> a=[1, 2, 3]
from __future__ import annotations
from typing import List
from pydantic import BaseModel
class Model(BaseModel):
a: List[int]
print(Model(a=('1', 2, 3)))
#> a=[1, 2, 3]
在内部,pydantic将调用类似于 typing.get_type_hints 的方法来解析注解。
在引用类型尚未定义的情况下,可以使用 ForwardRef (尽管在自引用模型的情况下直接引用类型或通过它的字符串引用是一个更简单的解决方案)。
在某些情况下,一个 ForwardRef 将不能在模型创建期间被解析。例如,当模型将自身引用为字段类型时,就会发生这种情况。当这种情况发生时,您需要在模型创建后调用 update_forward_refs,然后才能使用它:
from typing import ForwardRef
from pydantic import BaseModel
Foo = ForwardRef('Foo')
class Foo(BaseModel):
a: int = 123
b: Foo = None
Foo.update_forward_refs()
print(Foo())
#> a=123 b=None
print(Foo(b={'a': '321'}))
#> a=123 b=Foo(a=321, b=None)
警告
为了将字符串(类型名称)解析为注解(类型),pydantic需要一个名称空间字典来执行查找。 为此,它使用
module.__dict__,就像get_type_hints一样。 这意味着pydantic可能无法与模块的全局范围中未定义的类型配合使用。
例如,下面的实例可以正常运行:
from __future__ import annotations
from typing import List # <-- List is defined in the module's global scope
from pydantic import BaseModel
def this_works():
class Model(BaseModel):
a: List[int]
print(Model(a=(1, 2)))
而下面的则不行:
from __future__ import annotations
from pydantic import BaseModel
def this_is_broken():
# List is defined inside the function so is not in the module's
# global scope!
from typing import List
class Model(BaseModel):
a: List[int]
print(Model(a=(1, 2)))
解决这个问题超出了pydantic的要求:要么删除 future 的导入,要么全局声明类型。
python-devtools( pip install devtools )提供了许多在python开发期间有用的工具,包括 debug() 。这是 print() 的一个替代品,它能提供更易阅读的格式化输出,并显式打印语句位于哪个文件的哪个行上,以及打印了什么值。
pydantic通过在大多数公共类上实现 __pretty__ 方法与 devtools 集成。
特别是在检查模型时,debug() 很有用:
from datetime import datetime
from typing import List
from pydantic import BaseModel
from devtools import debug
class Address(BaseModel):
street: str
country: str
lat: float
lng: float
class User(BaseModel):
id: int
name: str
signup_ts: datetime
friends: List[int]
address: Address
user = User(
id='123',
name='John Doe',
signup_ts='2019-06-01 12:22',
friends=[1234, 4567, 7890],
address=dict(street='Testing', country='uk', lat=51.5, lng=0),
)
debug(user)
print('\nshould be much easier read than:\n')
print('user:', user)
将会在终端打印如下输出:
docs/examples/devtools_main.py:31 <module>
user: User(
id=123,
name='John Doe',
signup_ts=datetime.datetime(2019, 6, 1, 12, 22),
friends=[
1234,
4567,
7890,
],
address=Address(
street='Testing',
country='uk',
lat=51.5,
lng=0.0,
),
) (User)
should be much easier read than:
user: id=123 name='John Doe' signup_ts=datetime.datetime(2019, 6, 1, 12, 22) friends=[1234, 4567, 7890] address=Address(street='Testing', country='uk', lat=51.5, lng=0.0)
基准代码。 随意建议更多软件包以进行基准测试或改进现有软件包。
基准测试是使用Python 3.7.4运行的,上面列出的软件包版本是通过pypi在Ubuntu 18.04上安装的。
英文文档。
官方插件页面和Github存储库中找到更多信息。
datamodel-code-generator 项目是一个库和命令行实用程序,可从几乎任何数据源生成pydantic模型,包括:
- OpenAPI 3 (YAML/JSON)
- JSON 模式
- JSON/YAML 数据 (将会转变为 JSON 模式)
datamodel-code-generator 项目是一个库和命令行实用程序,可从几乎任何数据源生成pydantic模型,包括:
- OpenAPI 3 (YAML/JSON)
- JSON 模式
- JSON/YAML 数据 (将会转变为 JSON 模式)
当您发现自己有任何JSON可转换数据但没有pydantic模型时,此工具将允许您根据需要生成类型安全的模型层次结构。
7.1 安装
pip install datamodel-code-generator
- 1
7.2 示例
在这种情况下,datamodel-code-generator 从一个 JSON 模式文件创建 pydantic 模型:
Person.json:
{
"$id": "person.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"first_name": {
"type": "string",
"description": "The person's first name."
},
"last_name": {
"type": "string",
"description": "The person's last name."
},
"age": {
"description": "Age in years.",
"type": "integer",
"minimum": 0
},
"pets": {
"type": "array",
"items": [
{
"$ref": "#/definitions/Pet"
}
]
},
"comment": {
"type": "null"
}
},
"required": [
"first_name",
"last_name"
],
"definitions": {
"Pet": {
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
}
}
}
}
}
model.py:
# generated by datamodel-codegen:
# filename: person.json
# timestamp: 2020-05-19T15:07:31+00:00
from __future__ import annotations
from typing import Any, List, Optional
from pydantic import BaseModel, Field, conint
class Pet(BaseModel):
name: Optional[str] = None
age: Optional[int] = None
class Person(BaseModel):
first_name: str = Field(..., description="The person's first name.")
last_name: str = Field(..., description="The person's last name.")
age: Optional[conint(ge=0)] = Field(None, description='Age in years.')
pets: Optional[List[Pet]] = None
comment: Optional[Any] = None