FastAPI从入门到实战(2)——Pydantic模型

2023-11-06

前面了解了一下python的类型提示,这里就接着记录一下Pydantic这个用来执行数据校验的库。而且FastAPI就是基于python的类型提示和Padantic实现的数据验证。

简介

  • 官网:https://pydantic-docs.helpmanual.io/

  • Pydantic就是一个基于Python类型提示来定义数据验证、序列化和文档(使用JSON模式)的库;

  • 使用Python的类型提示来进行数据校验和settings管理;

  • 可以在代码运行的时候提供类型提示,数据校验失败的时候提供友好的错误提示;

  • 定义数据应该如何在纯规范的Python代码中保存,并用Pydantic验证;

基本用法

  • 数据规范的情况

    这里的**符号是为了分配参数用的,可以分配字典

# -*- coding: utf-8 -*-
# @Time: 2022/11/23 15:42
# @Author: MinChess
# @File: pydantic_tutorial.py
# @Software: PyCharm

from pydantic import BaseModel
from datetime import datetime
from typing import List,Optional

class User(BaseModel):
    id: int #必填字段(无默认值的时候,其为必填字段)
    name: str = "MinChess" #有默认值,选填字段
    signup_ts: Optional[datetime] = None
    friends: List[int] = [] # 列表中的元素需要是int类型或者能转换为int类型的str

external_data = {
    "id":"123",
    "signuo_ts": "2011-2-12 12:23:20",
    "friends": [1,2,'3']
}

user = User(**external_data)
print(user.id,user.friends)
print(repr(user.signup_ts))
print(user.dict())

运行结果:

123 [1, 2, 3]
None
{'id': 123, 'name': 'MinChess', 'signup_ts': None, 'friends': [1, 2, 3]}

字符串类型的数据也转为了int型

  • 数据不规范:id不为int类型或可转为int的str类型
external_data = {
    "id":"123h",
    "signuo_ts": "2011-2-12 12:23:20",
    "friends": [1,2,'3']
}

输出:

Traceback (most recent call last):
  File "E:\project\PythonProject\FastApiProject\pydantic_tutorial.py", line 23, in <module>
    user = User(**external_data)
  File "pydantic\main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User
id
  value is not a valid integer (type=type_error.integer)

报错说id是int型,这里就可以看出,提示和规范还是非常友好的了

校验失败处理

  • 给属性赋错误类型
try:
    User(id=1,signup_ts=datetime.now(),friends=[1,5,'dsd']) # 直接给属性赋值
except ValidationError as e:
    print(e.json()) # 错误json格式化
  • 输出结果:
[
  {
    "loc": [
      "friends",
      2
    ],
    "msg": "value is not a valid integer",
    "type": "type_error.integer"
  }
]

模型类的属性和方法

  • 解析和转换
print(user.dict()) # 转换为字典
print(user.json()) # 转换为json
print(user.copy()) # 浅copy

print(User.parse_obj(obj=external_data)) # 直接解析字典数据
print(User.parse_raw('{"id": 123, "name": "MinChess", "signup_ts": null, "friends": [1, 2, 3]}')) # 解析标准格式的数据,里面是双引号

path = Path('pydantic_tutorial.json')
path.write_text('{"id": 123, "name": "MinChess", "signup_ts": null, "friends": [1, 2, 3]}')
print(User.parse_file(path)) # 解析文件

print(user.schema()) #此方法用来告诉我们实例的数据格式的方案
print(user.schema_json())

user_data = {"id": 123, "name": "MinChess", "signup_ts": "2022-12-20 12:12:30", "friends": [1, 2, 3]}
print(User.construct(**user_data)) # 此方法不校验数据,直接创建模型类

print(User.__fields__.keys()) # (这里查看所有字段)定义模型类的时候,所有字段都注明类型,字段顺序就不会乱
  • 输出:
{'id': 123, 'name': 'MinChess', 'signup_ts': None, 'friends': [1, 2, 3]}
{"id": 123, "name": "MinChess", "signup_ts": null, "friends": [1, 2, 3]}
id=123 name='MinChess' signup_ts=None friends=[1, 2, 3]
id=123 name='MinChess' signup_ts=None friends=[1, 2, 3]
id=123 name='MinChess' signup_ts=None friends=[1, 2, 3]
id=123 name='MinChess' signup_ts=None friends=[1, 2, 3]
{'title': 'User', 'type': 'object', 'properties': {'id': {'title': 'Id', 'type': 'integer'}, 'name': {'title': 'Name', 'default': 'MinChess', 'type': 'string'}, 'signup_ts': {'title': 'Signup Ts', 'type': 'string', 'format': 'date-time'}, 'friends': {'title': 'Friends', 'default': [], 'type': 'array', 'items': {'type': 'integer'}}}, 'required': ['id']}
{"title": "User", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "default": "MinChess", "type": "string"}, "signup_ts": {"title": "Signup Ts", "type": "string", "format": "date-time"}, "friends": {"title": "Friends", "default": [], "type": "array", "items": {"type": "integer"}}}, "required": ["id"]}
id=123 name='MinChess' signup_ts='2022-12-20 12:12:30' friends=[1, 2, 3]
dict_keys(['id', 'name', 'signup_ts', 'friends'])

递归模型

  • 创建递归
class Sound(BaseModel):
    sound:str

class Dog(BaseModel):
    birthday: date
    weight: float = Optional[None]
    sound: List[Sound]

dogs = Dog(birthday=date.today(),weight=6.25,sound=[{"sound":"wang wang"},{"sound":"ying ying"}])
print(dogs.json())
  • 输出
{"birthday": "2022-11-23", "sound": [{"sound": "wang wang"}, {"sound": "ying ying"}]}

ORM模型

ORM 全称 Object Relational Mapping, 叫对象关系映射。简单的说,ORM 将数据库中的表与面向对象语言中的类建立了一种对应关系。

  • 利用sqlalchemy创建模型

Base = declarative_base()

class CompanyOrm(Base):
    __tablename__ = 'companies'
    id = Column(Integer,primary_key = True,nullable = False)
    public_key = Column(String(20),index = True,nullable = False ,unique = True)
    name = Column(String(63),unique=True)
    domains = Column(ARRAY(String(255)))

class CompanyModel(BaseModel):
    id:int
    public_key:constr(max_length=20)
    name:constr(max_length=63)
    domains:List[constr(max_length=255)]

    class Config:
        orm_mode = True

co_orm = CompanyOrm(
    id = 12,
    public_key= 'dddddd',
    name= 'MinChess',
    domains=['eeeeeee','fffffff']
)

print(CompanyModel.from_orm(co_orm))
  • 输出
id=12 public_key='dddddd' name='MinChess' domains=['eeeeeee', 'fffffff']

Pydantic支持的所有字段类型

Pydantic支持很多类型的数据,除了常用的那些基本类型外,还有一些不常用的类型,具体参看官网:

https://pydantic-docs.helpmanual.io/usage/types/

image-20221123170940674

源码

# -*- coding: utf-8 -*-
# @Time: 2022/11/23 15:42
# @Author: MinChess
# @File: pydantic_tutorial.py
# @Software: PyCharm

from pydantic import BaseModel,ValidationError,constr
from datetime import datetime,date
from pathlib import Path
from typing import List,Optional
from sqlalchemy import Column,Integer,String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.declarative import declarative_base

class User(BaseModel):
    id: int #必填字段(无默认值的时候,其为必填字段)
    name: str = "MinChess" #有默认值,选填字段
    signup_ts: Optional[datetime] = None
    friends: List[int] = [] # 列表中的元素需要是int类型或者能转换为int类型的str

external_data = {
    "id":"123",
    "signuo_ts": "2011-2-12 12:23:20",
    "friends": [1,2,'3']
}

user = User(**external_data)
print("====="*6,'基本使用','====='*6)
print(user.id,user.friends)
print(repr(user.signup_ts))
print(user.dict())

print("====="*6,'校验失败处理','====='*6)
try:
    User(id=1,signup_ts=datetime.now(),friends=[1,5,'dsd']) # 直接给属性赋值
except ValidationError as e:
    print(e.json()) # 错误json格式化

print("====="*6,'模型类的属性和方法','====='*6)
print(user.dict()) # 转换为字典
print(user.json()) # 转换为json
print(user.copy()) # 浅copy

print(User.parse_obj(obj=external_data)) # 直接解析字典数据
print(User.parse_raw('{"id": 123, "name": "MinChess", "signup_ts": null, "friends": [1, 2, 3]}')) # 解析标准格式的数据,里面是双引号

path = Path('pydantic_tutorial.json')
path.write_text('{"id": 123, "name": "MinChess", "signup_ts": null, "friends": [1, 2, 3]}')
print(User.parse_file(path)) # 解析文件

print(user.schema()) #此方法用来告诉我们实例的数据格式的方案
print(user.schema_json())

user_data = {"id": 123, "name": "MinChess", "signup_ts": "2022-12-20 12:12:30", "friends": [1, 2, 3]}
print(User.construct(**user_data)) # 此方法不校验数据,直接创建模型类

print(User.__fields__.keys()) # (这里查看所有字段)定义模型类的时候,所有字段都注明类型,字段顺序就不会乱

print("====="*6,'递归模型','====='*6)

class Sound(BaseModel):
    sound:str

class Dog(BaseModel):
    birthday: date
    weight: float = Optional[None]
    sound: List[Sound]

dogs = Dog(birthday=date.today(),weight=6.25,sound=[{"sound":"wang wang"},{"sound":"ying ying"}])
print(dogs.json())

print("====="*6,'ORM模型','====='*6)

Base = declarative_base()

class CompanyOrm(Base):
    __tablename__ = 'companies'
    id = Column(Integer,primary_key = True,nullable = False)
    public_key = Column(String(20),index = True,nullable = False ,unique = True)
    name = Column(String(63),unique=True)
    domains = Column(ARRAY(String(255)))

class CompanyModel(BaseModel):
    id:int
    public_key:constr(max_length=20)
    name:constr(max_length=63)
    domains:List[constr(max_length=255)]

    class Config:
        orm_mode = True

co_orm = CompanyOrm(
    id = 12,
    public_key= 'dddddd',
    name= 'MinChess',
    domains=['eeeeeee','fffffff']
)

print(CompanyModel.from_orm(co_orm))

感谢阅读
博客链接:https://blog.jiumoz.com/archives/fastapi-cong-ru-men-dao-shi-zhan-2pydantic-mo-xing

欢 迎 关 注 博 主 个 人 小 程 序!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FastAPI从入门到实战(2)——Pydantic模型 的相关文章

随机推荐

  • 吴恩达深度学习作业_吴恩达深度学习第一部分第二周作业打卡

    1 What does a neuron compute A A neuron computes the mean of all features before applying the output to an activation fu
  • keil不能进调试模式的解决方法

    一 问题现象 平时用烧录器调试程序一直都没问题 突然今天不能调试了 故障提示如下 二 问题分析 尝试过各种解决方法 插拔烧录器 更换烧录器 插拔stm32主机电源 重启keil开发环境 问题依旧 看来问题不应该在主机和烧录器上 最后问题定位
  • spec文件

    spec文件 spec文件是配置规范文件 是RPM软件包编译过程的核心 它说明了软件包如何被配置 打那些补丁 安装哪些文件 安装到哪里 安装过程需要哪些系统级别活动 标签说明 依赖关系 Dependencies BuildRequires
  • 线上项目路由跳转报错 Loading chunk failed

    场景 线上PC端项目点击左侧路由菜单栏进行页面跳转时点击无反应并报错 Loading chunk failed 原因 经查阅资料找出原因 项目使用了路由懒加载 路由懒加载的情况下 访问当前应用进行路由跳转时都是实时动态的从服务器上拉取相应模
  • Python 递归函数返回值为 None 的解决办法

    在使用 Python 开发的过程中 避免不了会用到递归函数 但递归函数的返回值有时会出现意想不到的情况 下面来举一个例子 gt gt gt def fun i i 1 if i lt 5 fun i else return i gt gt
  • 【转载】做好功能测试,这8项必备技能了解一下!

    原文链接 功能测试是测试工程师的基础功 很多人功能测试还做不好 就想去做性能测试 自动化测试 很多人对功能测试的理解就是点点点 如何自己不用心去悟 去研究 那么你的职业生涯也就停留在点点点上了 在这里 我把我对功能测试的理解写下来 那么 功
  • Can not load Open Client,please verify that libct.dll and libcs.dll are in your

    Can not load Open Client please verify that libct dll and libcs dll are in your path Please make sure your version of Op
  • C++ 函数模板与类模板template,以及具体化、实例化

    函数模板 需要创建针对不同参数类型的实现相同功能的不同函数 注 模板不能缩短可执行程序 最终仍是有多个独立的函数定义 另 若对不同类型的参数执行不同的算法 可以重载模板定义 前提是两函数的特征标不同 例 template
  • arduino+oled显示字

    OLED 显示屏有四个引脚 分别是 SDA 数据线 SCK 时钟线 VDD 3 3V GND 在UNO开发板上I2C接口 SDA对应D4 SCK对应D5 在MEGA2560开发板上I2C接口 SDA对应D20 SCL对应D21 首先下载一个
  • 随笔 笔记

    一 ES6数组去重结果 new set array 二 cmd 管理员身份运行 ipconfig flushdns 刷新dns 有时某个网站进不去就刷新一下 比如echarts中文官网 三 检查元素中 快速搜索文件所在位置 浏览器打开 f1
  • 顶尖程序员不同于常人的 5 个区别

    2019独角兽企业重金招聘Python工程师标准 gt gt gt The Effective Engineer 的作者在写书的过程中 为了了解那些顶级程序员和普通程序员的区别 采访了很多硅谷顶级科技公司的顶尖软件工程师 他发现这些给世界带
  • Rust 移动零

    给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 请注意 必须在不复制数组的情况下原地对数组进行操作 力扣https leetcode cn problems move zeroes Rust代码
  • Java事件处理和事件派发机制

    事件处理 GUI程序是事件驱动程序 因此我们需要学习Java的事件处理 常见的事件包括 移动鼠标 单双击鼠标各个按钮 单击按钮 在文本字段输入 Swing通过事件对象来包装事件 程序可以通过事件获取事件的有关信息 事件处理的几个要素 事件源
  • python中16mod7_Python小白学习之路(十六)—【内置函数一】

    将68个内置函数按照其功能分为了10类 分别是 数学运算 7个 abs divmod max min pow round sum 类型转换 24个 bool int float complex str bytearray bytes mem
  • 现代C++之SFINAE应用(小工具编写)

    现代C 之SFINAE应用 小工具编写 0 导语 现在考虑这个输入 map
  • 【计算机毕业设计】-java家教系统视频教程-手把手教你制作

    很多大四同学苦于没有参考的毕设资料 或者下载的资料不全 代码有问题 数据有问题等等 造成毕设出现问题影响大学毕业 现在 免费提供项目源码和视频教程 让大家在短时间内可以完成自己的毕业设计 对于java方向的毕业设计题目选题 我们可以从技术点
  • java javax.mail包报错550 Mailbox not found or access denied

    java javax mail包报错550 Mailbox not found or access denied 报错信息如下所示 拦截异常信息 获取发送失败的邮箱地址 进行打印 未发送成功的邮箱地址进行重发 或者可以直接将无效的邮箱从数据
  • 输入2 个字符串S1 和S2,要求删除字符串S1 中出现的所有子串S2

    输入2 个字符串S1 和S2 要求删除字符串S1 中出现的所有子串S2 题目内容 输入2 个字符串S1 和S2 要求删除字符串S1 中出现的所有子串S2 即结果字符串中不能包含S2 提示 输入数据的设计使得不可能出现输出为空的情况 输入格式
  • 在本地wz-dev分支拉取远程dev总分支最新代码的流程

    文章目录 0 图片说明 1 在wz dev分支上进行git add 和git commit m 2 切换到dev分支 拉取代码 与本地wz dev代码进行合并 推送合并后的代码到远程dev分支 3 切换到wz dev分支 与dev分支合并
  • FastAPI从入门到实战(2)——Pydantic模型

    前面了解了一下python的类型提示 这里就接着记录一下Pydantic这个用来执行数据校验的库 而且FastAPI就是基于python的类型提示和Padantic实现的数据验证 简介 官网 https pydantic docs help