Pydantic官方文档


Pydantic官方文档

 

email-validator。
  • 要在 Python3.8之前的版本中使用 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=Trueroot_validators 定制类验证。在这种情况下,validator 函数将被传递一个可以复制和修改的GetterDict 实例。

    pickle 的官方文档,“pickle模块对于错误或恶意构造的数据是不安全的。切勿从不可信或未经身份验证的来源获取数据。”

    注意

    由于它可能导致任意代码的执行,因此作为一种安全措施,您需要显式地将 allow_pickle 传递给解析函数,以便加载pickle数据。

    samuelcolvin/pydantic#1047。

    字段可以由 (, ) 形式的元组定义,也可以仅由默认值定义。__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 对象时
      • intfloat:假定为 Unix 时间时。例如,自1970年1月1日以来的秒数 (如果 >= -2e10 或 <= 2e10) 或毫秒数 (如果 < -2e10 或 > 2e10)。
      • str:下面的格式可用时:
        • YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
        • 作为字符串的 intfloats (假定为Unix time)
    • date 字段可以是:
      • date:存在 date 对象时
      • intfloat: 参见 datetime
      • str:下面的格式可用时:
        • YYYY-MM-DD
        • intfloat 参见 datetime
    • time 字段可以是:
      • time:存在 time 对象时
      • str:下面的格式可用时:
        • HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]
    • timedelta 字段可以是:
      • timedelta:存在 timedelta 对象时
      • intfloat:假定为"秒"
      • 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。

    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 对象,该对象有两个属性:nameemail。对于 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

    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_hsl

      hsl(, , ) 格式的字符串。如果设置了 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

    基于BIN,PaymentCardBrand 可以是以下之一:

    • PaymentCardBrand.amex
    • PaymentCardBrand.mastercard
    • PaymentCardBrand.visa
    • PaymentCardBrand.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
  • JSON Schema Validation
  • OpenAPI
  • 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
  • JSON Schema Validation
  • OpenAPI Data Types
  • 标准的 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

    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-dotenvpip 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支持通过两种方式加载该文件:

    1. 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
    2. 使用 _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]
     

     

    在内部,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 模式)

    当您发现自己有任何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