Pydantic学习

Pydantic 是一个 Python 的数据验证和模型声明库,旨在建立正确使用对象化方法的简单,快速,和可扩展方式。

它可以省去你把琐碎数据验证任务,保证你的数据总是整洁有序。Pydantic为你提供一种更优雅的方式完成你的任务,使你可以专注于开发解决方案,而不是验证数据的任务。

Pydantic可以用来定义模型,以便于格式化数据并转换成Python数据对象。它也可以在输入和输出之间执行类型转换,并根据你定义的规则进行数据验证。

你可以按照你的需要定义模型,你可以快速创建精确和可扩展的域,包括验证数据格式,类型,值和翻译字段。你可以在域之间建立灵活性,允许交叉验证和明智的行为定义。

Pydantic还允许自定义验证器,装饰器和hooks,并且可以与其他任何使用python的模型框架胶接,这使你可以根据自己的需要创造多层结构。

Pydantic有众多的优点,既可用于大型项目,也可用于简单项目。一个重要的一点,它可以很容易地扩展,也可以允许简单的复制/粘贴套件,从而节省很多时间。此外,所有的数据和关系都能被使用者轻松识别。

总的来说,Pydantic可以让你省去大量时间,以更简单的方式进行数据验证,这样你就可以将更多的精力放在实现自己的想法上

简单上手

from pydantic import BaseModel


class Index(BaseModel):
    id: int | None  # 表示id这个属性为int类型,如果不符合会强制转换为该类型,默认是None,可以不传
    type_number: str | None  # 表示type_number属性为str类型,如果不符合会强制转换为该类型,默认None,可以不传
    fruit: list  # 表示fruit属性为列表,如果不符合会强制转化,默认不为None,为必须传入的参数
    name = 'jason'  # name属性有个默认值,如果不传入使用默认,传入则更改

下来我们来针对上面的代码,进行测试

必要参数与默认None参数
# type_number默认为None,不传入不会报错
obj = Index(id=1, fruit=['苹果', '香蕉'])
print(obj.id)  # 1 
print(type(obj.id))  # <class 'int'>
print(obj.fruit)  # ['苹果', '香蕉']
print(type(obj.fruit))  # <class 'list'>
# fruit默认不为None,不传入会报错
obj = Index(id=1, type_number='9527')

# 报错信息,提示的很明显,fruit参数必传
fruit
  field required (type=value_error.missing)
传入与预期类型不同的参数
# id预期是int,我们传入str
obj = Index(id='3', fruit=['苹果'])
print(obj.id)  # 3
print(type(obj.id))  # <class 'int'>
print(obj.fruit)  # ['苹果', '香蕉']
print(type(obj.fruit))  # <class 'list'>

这个时候我们发现,当我们传入的是字符串类型的时候,当我们产生属性的时候,会直接将字符串转为我们期望的int类型,进行类型强转,但是如果是无法转换的会报错,如下

obj = Index(id='a', fruit=['苹果'])
# 报错,会直接告诉我们是哪个参数错误,错误的类型
id
  value is not a valid integer (type=type_error.integer)

针对列表内的数据类型也是可以做限制的,如下

class Index(BaseModel):
    id: int | None  
    type_number: str | None  
    fruit: List[str] | None  入的参数  # 这里我们限制了list内部的类型必须为str
    name = 'jason' 

obj = Index(id='1', fruit=['苹果', 1])
print(obj.id)  # 3
print(type(obj.id))  # <class 'int'>
print(obj.fruit)  # ['苹果', '1']
print(type(obj.fruit))  # <class 'list'>

我们可以看到在上面的代码中,我们传入的list内部参数是str与int,但是当我们真正打印出来的时候列表内的int已经被转换为了str

关于类型转换

当我们上述操作进行的时候,我想到了我们声明了数据类型,然后如果不一致转换,那我们有没有办法自己进行数据类型的转换呢,我查看到pydantic中的validator装饰器,可以对单个数据值进行处理,下面我尝试了一下

from pydantic import BaseModel, validator
from typing import List


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: List[str] | None
    name = 'jason'

    @validator('fruit')
    @classmethod
    def convert_type(cls, value):
        print('触发')
        if value is None:
            return None
        if not isinstance(value, list):
            try:
                value = [value]
            except Exception:
                raise TypeError('传入的类型错误')
        return value

obj = Index(id=1, fruit='苹果')
# 会直接报错,报错内容如下,证明还是我们的参数错误
fruit
  value is not a valid list (type=type_error.list)

当我按照我的想法尝试的时候,发现一个问题,当我们传入的参数并不是我们预期想要要求的参数,他并没有执行'触发的打印操作',会直接报错,不会走我们写的类型转化的参数,当我做以下修改的时候他就可以进行类型的转化

from pydantic import BaseModel, validator
from typing import List,Union


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: Union[List[str], str] | None  # 类型注释改为允许str或List[str]
    name = 'jason'

    @validator('fruit')
    @classmethod
    def convert_type(cls, value):
        print('触发')  # 打印了
        if value is None:
            return None
        if isinstance(value, str):
            return [value]
        return value


# id预期是int,我们传入str
obj = Index(id=1, fruit='苹果')
print(obj.id)  # 3
print(type(obj.id))  # <class 'int'>
print(obj.fruit)  # ['苹果']
print(type(obj.fruit))  # <class 'list'>

这个时候我们发现,是调用了我们写的函数,进行类型转换,我们主要在声明的时候进行了一个修改,我们对于fruit的属性声明修改为了可以接收list或者str,所以我们可以得到一个结论pydantic对于属性类型的转换是优先于validator装饰的函数,这样对于传入的类型参数限制会更好一点

在上面我代码中我们使用Union:

Union是Python中typing模块中的一种类型,用于声明多个可能的类型。它允许您指定一个变量可以具有多种类型中的任何一种

如果您希望一个变量可以是整数或字符串类型,您可以使用Union[int, str]来声明该变量的类型。这意味着该变量可以接受整数或字符串的值

我们除了Union还可以使用Any:

Any 是 Python 中的一种特殊类型注解,表示可以是任何类型的对象。在类型注解中使用 Any 表示该变量可以接受任意类型的值,相当于取消了类型检查。使用 Any 类型注解的变量可以接受任意类型的值,不会触发类型错误

validator其他用法

刚才我们使用了pydantic中的validator进行数据值的校验,我们进行了单个值,其实我们还是可以进行多个值的校验

from pydantic import BaseModel, validator
from typing import List, Union


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: Union[List[str], str] | None  # 类型注释改为允许str或List[str]
    name = 'jason'

    @validator('fruit', 'id', )
    @classmethod
    def convert_type(cls, value):
        print(value)
        print('触发')  # 打印了
        if value is None:
            return None
        if isinstance(value, str):
            return [value]
        return value


# id预期是int,我们传入str
obj = Index(id=1, fruit='苹果')
print(obj.id)
print(type(obj.id)) 
print(obj.fruit)
print(type(obj.fruit)) 

下面是打印信息

1    这里是id的值
触发
苹果   这里是fruit的值
触发
1
<class 'int'>
['苹果']
<class 'list'>

我们查看打印信息,当我们使用validator进行多个属性值的校验的时候, 他会把validator括号中的值按照我们类中定义的属性的顺序来进行调用函数校验,因为我故意把装饰器中的参数顺序写反但是还是会优先打印id的值,如果我再修改代码

from pydantic import BaseModel, validator
from typing import List, Union


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: List[str] | None
    # fruit: Union[List[str], str] | None  # 类型注释改为允许str或List[str]
    name = 'jason'

    @validator('fruit', 'id', )
    @classmethod
    def convert_type(cls, value):
        print(value)
        print('触发')  # 打印了
        if value is None:
            return None
        if isinstance(value, str):
            return [value]
        return value


# id预期是int,我们传入str
obj = Index(id=1, fruit='苹果')
print(obj.id)
print(type(obj.id))
print(obj.fruit)
print(type(obj.fruit))

打印信息

1
触发

 File "pydantic\main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Index
fruit
  value is not a valid list (type=type_error.list)

通过这两步我们可以发现,其实pydantic他的validator校验其实还是按照产生的顺序来进行的,我们上面的例子,他首先会校验id值是否符合预期,符合预期再调用我们的validator装饰函数校验,然后再会进行fruit属性值的校验,所以打印才会打印id的值,然后打印触发,当fruit的属性值就会不符合预期直接报错

root_validator装饰器

简单用法

from pydantic import BaseModel, validator, root_validator
from typing import List, Union


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: Union[List[str], str] | None  # 类型注释改为允许str或List[str]
    name = 'jason'
    
    @root_validator
    @classmethod
    def conver_value(cls, value):
        print(value, 'conver_value')
        # {'id': 1, 'type_number': None, 'fruit': ['苹果'], 'name': 'jason'} conver_value
        print(type(value))
        # <class 'dict'>
        print(value.get('id'))
        # 1
        return value

obj = Index(id=1, fruit='苹果')


我们可以看到当我们使用root_validator装饰以后,我们的校验函数中的value值其实就是我们传入的所有参数,这个参数的类型是一个字典,所以我们直接使用字典的get方法就可以取到我们传入的属性值,然后对于该值进行一系列的校验

那关于validator和root_validator的执行顺序应该是什么样的呢,我们也可以通过代码试出来

from pydantic import BaseModel, validator, root_validator
from typing import List, Union


class Index(BaseModel):
    id: int | None
    type_number: str | None
    fruit: Union[List[str], str] | None  # 类型注释改为允许str或List[str]
    name = 'jason'

    @validator('fruit', 'id', )
    @classmethod
    def convert_type(cls, value):
        print(type(value))
        print('触发convert_type')
        if value is None:
            return None
        if isinstance(value, str):
            return [value]
        return value

    @root_validator
    @classmethod
    def conver_value(cls, value):
        print('触发conver_value')
        print(value)
        return value


obj = Index(id=1, fruit='苹果')

我们现在来看打印信息就可以看到他们的执行顺序了

<class 'int'>
触发convert_type
<class 'str'>
触发convert_type
{'id': 1, 'type_number': None, 'fruit': ['苹果'], 'name': 'jason'}
触发conver_value

我们可以看到因为validator两个参数所以他打印了两次,而且我们也可以通过fruit的值来看到再conver_value函数中他的值已经是列表了,所以我们可以得出一个结论

执行顺序

1.先执行pydactic的类型校验,如果不符合类型进行强制转换,无法转换则会报错

2.执行validator装饰的函数,validator装饰器中的参数要定义为我们的属性值,这里拿到的value已经是符合我们预期的数据类型了

3.执行root_validator装饰的函数,这里的value是经过上述两步操作之后的数据,他是一个字典的形式,键是我们定义的属性名,值是我们传入的属性值

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Pydantic是一个Python库,用于数据验证和解析。它提供了一种简单且强大的方式来定义数据模型,并且可以验证输入数据的有效性。通过使用Pydantic,您可以轻松地定义和处理复杂的数据结构。 安装Pydantic的扩展功能可以通过pip命令来完成,例如安装邮件验证支持可以使用以下命令:pip install pydantic[email]。同样地,您也可以安装dotenv文件支持或同时安装多个扩展功能。 Pydantic的核心类是BaseSettings类,它允许在验证请求数据和加载系统设置的上下文中使用。在验证请求数据的上下文中,您可以使用基本数据类型进行验证。而在加载系统设置的上下文中,您可以从环境变量中读取设置,并且还可以处理更复杂的对象,例如DSN和Python对象。 一个很大的优势是,Pydantic的模型的定义与Python的类型提示密切相关。如果您熟悉使用Python类型提示,那么您就知道如何使用Pydantic。数据结构只是使用类型注释定义的类的实例,因此自动完成、linting、mypy、IDE(尤其是PyCharm)和您的直觉都应该与您的验证数据正常工作。您无需学习新的模式定义微语言,只需使用Python类型提示即可定义数据模型。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python中pydantic库](https://blog.csdn.net/qq_62789540/article/details/127069443)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值