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)
    """

被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)
    """
  • 可以给 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. 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. 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'
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastAPI是一个现代、快速(高性能)的Web框架,用于构建API。它基于Python 3.7+的类型提示和异步支持,提供了简单易用的API开发体验。FastAPI具有以下特点: 1. 快速:FastAPI使用基于Starlette的异步请求处理器,可以处理大量并发请求,并具有出色的性能。 2. 类型提示:FastAPI使用Python的类型提示功能,可以在编译时进行类型检查,并提供自动生成API文档的功能。 3. 自动文档生成:FastAPI可以根据代码中的类型提示和注释自动生成交互式API文档,包括请求和响应模型、参数验证等。 4. 异步支持:FastAPI完全支持异步编程,可以使用async/await语法编写异步代码,提高性能和并发处理能力。 5. 安全性:FastAPI内置了常见的安全功能,如身份验证、授权等,并提供了易于使用的方式来保护API。 6. 数据验证:FastAPI使用Pydantic库进行数据验证和转换,可以自动解析请求数据,并进行类型检查和转换。 7. WebSocket支持:FastAPI支持WebSocket协议,可以轻松地构建实时应用程序。 Pydantic是一个用于数据验证和解析的Python库,它与FastAPI紧密集成。Pydantic提供了一种声明性的方式来定义数据模型,可以自动进行数据验证、类型转换和文档生成。Pydantic具有以下特点: 1. 声明性:Pydantic使用Python的类型提示来定义数据模型,可以在编译时进行类型检查,并提供自动生成文档的功能。 2. 数据验证Pydantic可以自动验证输入数据的类型、长度、格式等,并提供友好的错误提示。 3. 数据转换:Pydantic可以自动将输入数据转换为指定的类型,如字符串转整数、字符串转日期等。 4. 文档生成:Pydantic可以根据数据模型自动生成文档,包括字段说明、类型信息等。 5. 序列化和反序列化:Pydantic提供了方便的方法来将数据模型转换为JSON、XML等格式,并支持从这些格式解析数据模型。 总结起来,FastAPI是一个快速、现代化的Web框架,而Pydantic是一个用于数据验证和解析的库。它们可以一起使用,提供了简单易用的API开发体验,并自动生成交互式API文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值