• pydantic 数据验证


    官网

    如果你正在做接口开发,或者任何函数的开发,总会遇到需要判断参数是否正确的问题。一个一个验证不是很合理,所幸有pydantic这个包可以帮我们完成这项工作,而且是完美的完成

    使用验证器装饰器可以实现对象之间的自定义验证和复杂关系。

    1. validator装饰器
    from pydantic import BaseModel, ValidationError, validator
    
    
    class UserModel(BaseModel):
        name: str
        username: str
        password1: str
        password2: str
    
        @validator('name')
        def name_must_contain_space(cls, name):
            if ' ' not in name:
                raise ValueError('must contain a space')
            return name.title()
    
        @validator('password2')
        def passwords_match(cls, v, values, **kwargs):
            if 'password1' in values and v != values['password1']:
                raise ValueError('passwords do not match')
            return v
    
        @validator('username')
        def username_alphanumeric(cls, v):
            assert v.isalnum(), 'must be alphanumeric'
            return v
    
    
    user = UserModel(
        name='samuel colvin',
        username='scolvin',
        password1='zxcvbn',
        password2='zxcvbn',
    )
    print(user)
    #> name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn'
    
    try:
        UserModel(
            name='samuel',
            username='scolvin',
            password1='zxcvbn',
            password2='zxcvbn2',
        )
    except ValidationError as e:
        print(e)
        """
        2 validation errors for UserModel
        name
          must contain a space (type=value_error)
        password2
          passwords do not match (type=value_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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    validator 包装的函数第二个参数是需要验证的字段的字段值

    你也可以将下列参数的任何子集添加到签名中(名称必须匹配):

    values:一个字典,包含任何以前验证过的字段的名称到值映射

    config:模型配置

    field:正在验证的字段。对象类型为pydantic.fields.ModelField。

    **kwargs:如果提供,这将包括签名中没有显式列出的上述参数

    1. Pre and per-item validators¶
    from typing import List
    from pydantic import BaseModel, ValidationError, validator
    
    
    class DemoModel(BaseModel):
        square_numbers: List[int] = []
        cube_numbers: List[int] = []
    
        # '*' is the same as 'cube_numbers', 'square_numbers' here:
        # 这里的pre=True指的是在做正式验证之前要走的函数
        @validator('*', pre=True)
        def split_str(cls, v):
            if isinstance(v, str):
                return v.split('|')
            return v
    
        @validator('cube_numbers', 'square_numbers')
        def check_sum(cls, v):
            if sum(v) > 42:
                raise ValueError('sum of numbers greater than 42')
            return v
    
        @validator('square_numbers', each_item=True)
        def check_squares(cls, v):
            assert v ** 0.5 % 1 == 0, f'{v} is not a square number'
            return v
    
        @validator('cube_numbers', each_item=True)
        def check_cubes(cls, v):
            # 64 ** (1 / 3) == 3.9999999999999996 (!)
            # this is not a good way of checking cubes
            assert v ** (1 / 3) % 1 == 0, f'{v} is not a cubed number'
            return v
    
    
    print(DemoModel(square_numbers=[1, 4, 9]))
    #> square_numbers=[1, 4, 9] cube_numbers=[]
    print(DemoModel(square_numbers='1|4|16'))
    #> square_numbers=[1, 4, 16] cube_numbers=[]
    print(DemoModel(square_numbers=[16], cube_numbers=[8, 27]))
    #> square_numbers=[16] cube_numbers=[8, 27]
    try:
        DemoModel(square_numbers=[1, 4, 2])
    except ValidationError as e:
        print(e)
        """
        1 validation error for DemoModel
        square_numbers -> 2
          2 is not a square number (type=assertion_error)
        """
    
    try:
        DemoModel(cube_numbers=[27, 27])
    except ValidationError as e:
        print(e)
        """
        1 validation error for DemoModel
        cube_numbers
          sum of numbers greater than 42 (type=value_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
    • 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
    • 可以给 validator添加多个字段,使这个validation作用于多个字段
    • validator也可以作用于所有字段,通过给validator传入*
    • pre参数将使这个validator比其他的validator先call
    • 通过传递each_item=True 将实现validator作用于 (e.g. of List, Dict, Set, etc.)的每个元素
    1. each_item 验证
    from typing import List
    from pydantic import BaseModel, ValidationError, validator
    
    
    class ParentModel(BaseModel):
        names: List[str]
    
    
    class ChildModel(ParentModel):
        @validator('names', each_item=True)
        def check_names_not_empty(cls, v):
            assert v != '', 'Empty strings are not allowed.'
            return v
    
    
    # This will NOT raise a ValidationError because the validator was not called
    try:
        child = ChildModel(names=['Alice', 'Bob', 'Eve', ''])
    except ValidationError as e:
        print(e)
    else:
        print('No ValidationError caught.')
        #> No ValidationError caught.
    
    
    class ChildModel2(ParentModel):
        @validator('names')
        def check_names_not_empty(cls, v):
            for name in v:
                assert name != '', 'Empty strings are not allowed.'
            return v
    
    
    try:
        child = ChildModel2(names=['Alice', 'Bob', 'Eve', ''])
    except ValidationError as e:
        print(e)
        """
        1 validation error for ChildModel2
        names
          Empty strings are not allowed. (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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1. Validation always

    出于性能原因,在没有提供值时,默认情况下不对字段调用验证器。然而,在有些情况下,它可能是有用的或需要总是调用验证器,例如设置一个动态默认值。

    from datetime import datetime
    
    from pydantic import BaseModel, validator
    
    
    class DemoModel(BaseModel):
        ts: datetime = None
    
        @validator('ts', pre=True, always=True)
        def set_ts_now(cls, v):
            return v or datetime.now()
    
    
    print(DemoModel())
    #> ts=datetime.datetime(2022, 9, 5, 18, 0, 25, 664356)
    print(DemoModel(ts='2017-11-08T14:00'))
    #> ts=datetime.datetime(2017, 11, 8, 14, 0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. Reuse validators(重用验证)

    有时,你会想在多个字段/模型上使用相同的验证器(例如规范化一些输入数据)。“天真”的方法是编写一个单独的函数,然后从多个装饰器调用它。显然,这需要大量的重复和样板代码。为了避免这种情况,在pydantic中添加了allow_reuse参数。

    from pydantic import BaseModel, validator
    
    
    def normalize(name: str) -> str:
        return ' '.join((word.capitalize()) for word in name.split(' '))
    
    
    class Producer(BaseModel):
        name: str
    
        # validators
        _normalize_name = validator('name', allow_reuse=True)(normalize)
    
    
    class Consumer(BaseModel):
        name: str
    
        # validators
        _normalize_name = validator('name', allow_reuse=True)(normalize)
    
    
    jane_doe = Producer(name='JaNe DOE')
    john_doe = Consumer(name='joHN dOe')
    assert jane_doe.name == 'Jane Doe'
    assert john_doe.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
    • 24
    • 25
  • 相关阅读:
    QT day3作业
    var、let、const关键字的特性,以及let、const暂时性死区的作用
    MySQL表的约束
    如何应对老板需求?
    【机器学习笔记】吴恩达机器学习
    vue-cli脚手架创建项目时报错Error: command failed: npm install --loglevel error
    Ajax 相关问题
    Kubernetes实战(三)-k8s节点设置cpu高于多少就不调度
    JVM内存和垃圾回收-05.虚拟机栈
    【MHA】MySQL高可用MHA介绍5-所有参数
  • 原文地址:https://blog.csdn.net/weixin_43632687/article/details/126890874