写点什么

FastAPI 开发中数据校验利器 Pydantic 介绍与集成使用

作者:宇宙之一粟
  • 2023-04-04
    中国香港
  • 本文字数:4319 字

    阅读完需:约 14 分钟

前言

当我们在处理一些数据来自系统外部的时候,可能来自 API、终端用户输入或者其他途径,Web 开发中有句话叫做:永远不要相信用户的输入


所以,我们可能需要检查、校验这些数据,将这些数据格式化、标准化,以至于这些数据满足我们真实程序的数据输入,保证项目的正确执行。

Pydantic 介绍

Pydantic 是一个 Python 库,它提供了一种简单方便的方法来验证和操作数据。它的创建是为了帮助简化数据验证过程并提高开发人员的效率。 Pydantic 与 Python 的数据结构无缝集成,并提供灵活且用户友好的 API 来定义和验证数据。使用 Pydantic,开发人员可以定义他们的数据结构和验证规则,库将自动验证传入数据并在不满足任何规则时引发错误。这有助于确保项目中使用的数据是一致的并符合要求的标准。



官方介绍:使用 Python 类型注释的数据验证和设置管理。 pydantic 在运行时强制执行类型提示,并在数据无效时提供用户友好的错误。定义数据应该如何在纯正的、规范的 Python 中;用 pydantic 验证它。


Pydantic 提供 BaseModel 让开发者能够通过继承该类并且利用 typing 注记类别属性的数据类型,保证我们不用写过多的代码就拥有基本的数据验证功能。


定义模型时,被用作请求主体对象和请求-响应对象的类型提示。在本文中,我们将简单看一下在请求体中使用 Pydantic 模型来处理 POST 请求。

Pydantic 安装

pip install pydantic
复制代码



但是如果你是直接安装好了 FastAPI ,这一步可以跳过,因为 FastAPI 框架就使用了 Pydantic。

Pydantic 优点

  • 易于使用: Pydantic 很容易安装与使用,并且有一个简单的 API,使得所有开发者都可以快速上手使用。

  • 快速验证: Pydantic 快速有效地执行数据验证,使其适合于在高性能的应用程序中使用。

  • 自动生成文档: Pydantic 可以为你的数据模型自动生成文档,节省时间,并且更容易理解你的数据结构。

  • 类型提示支持: Pydantic 支持类型提示,使开发人员更容易定义数据结构,避免在代码中出现错误。

  • 与 FastAPI 集成: Pydantic 可以很容易地与 FastAPI(一个高性能的 Python 网络框架)集成,为 API 提供自动请求和响应验证。

  • 自定义验证规则: Pydantic 允许开发人员定义自定义的验证规则,使得在需要的时候可以实现复杂的验证逻辑。

  • 一致的数据: Pydantic 确保项目中使用的数据是一致的,并符合所需的标准,减少了错误的风险,使代码库的维护更加容易。

什么是类型注解

Python 是动态类型的语言,所以在同一个命名空间中,变量的值可以是字符串也可以是数组,比如:


>>> x = 4>>> type(x)<class 'int'>>>> x = "hello, 宇宙之一粟">>> type(x)<class 'str'>
复制代码


大约在 Python 3.5 起引入了 type hints 类型注解,虽然 Python 在运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具,这些工具就可以帮助我们侦测类型上的错误。


最简单的注解方式如下:


def hello(name: str) -> str:    return 'Hello ' + name
复制代码


这里面的 : str 声明 name 字段为字符串,如果传入 int 类型,编译器就会得到报错:


利用 Pydantic 定义模型

我们在定义如下 Book 模型的时候,我们声明了 id 为数字类型,Name 到 ISBN 都为字符串类型,Tags 为列表类型,通过继承自 BaseModel 的特性,Pydantic 会自动帮我们验证型态的正确性:


from pydantic import BaseModel
class Book(BaseModel): id: int Name: str Author: str Publisher: str ISBN: str Tags: list[str]

HeadFirstPython = Book( id = 1, Name = 'Head First Python, 2nd Edition', Author = 'Paul Barry', Publisher ="O'Reilly Media, Inc.", ISBN = "9781491919538", Tags = ["Python", "Head Frist"])
复制代码


如果这样定义之后,我们的上述的 HeadFirstPython 不会报任何错误,但是如果我们的 id 还没定义,如下:


from pydantic import BaseModel
class Book(BaseModel): id: int Name: str Author: str Publisher: str ISBN: str Tags: list[str]

HeadFirstPython = Book( id = "notdefineyet", Name = 'Head First Python, 2nd Edition', Author = 'Paul Barry', Publisher ="O'Reilly Media, Inc.", ISBN = "9781491919538", Tags = ["Python", "Head Frist"])
复制代码


则会报一个 id 类型错误的报错:



但是如果你定义 id 为 id = "1", 则不会报错,因为 Pydantic 帮助我们自动实现了类型转换,如果想要严格控制 int 类型,需要导入 StrictIntStrictString 同理,代码如下:


from pydantic import BaseModel, StrictInt, StrictStr
class Book(BaseModel): # id: int id: StrictInt # Name: str Name: StrictStr Author: str Publisher: str ISBN: str Tags: list[str]

HeadFirstPython = Book( # id = "1", id = 1, # Name = 'Head First Python, 2nd Edition', Name = 27546, # 此处会报错, Author = 'Paul Barry', Publisher ="O'Reilly Media, Inc.", ISBN = "9781491919538", Tags = ["Python", "Head Frist", 1])
print('output>', HeadFirstPython.dict())
复制代码


报错信息如下:


pydantic.error_wrappers.ValidationError: 1 validation error for BookName  str type expected (type=type_error.str)
复制代码


更多 Pydantic 的类型详细说明,请查看官方文档,点此处

Pydantic 的工作方式

Pydantic 的工作方式是允许开发人员使用 Python 类来定义数据模型。这些类继承自 Pydantic 提供的 BaseModel 类,可以包括类型提示、默认值和验证规则。当收到数据时,Pydantic 使用数据模型来验证传入的数据,并确保其符合所定义的要求。


在验证过程中,Pydantic 对照数据模型中定义的类型提示和验证规则,检查数据中的每个字段。如果数据不符合要求,Pydantic 会提出一个错误,并停止验证过程。如果数据是有效的,Pydantic 就会创建一个数据模型的实例,用传入的数据来填充它,并将其返回给用户。


Pydantic 还提供了一些高级功能,例如字段别名,自定义验证函数,以及对嵌套数据模型的支持,使得它可以处理广泛的数据验证场景。此外,Pydantic 支持序列化和反序列化,允许根据需要将数据转换为 Python 数据结构、JSON 和其他格式。

Pydantic 与 FastAPI 集成开发:写一个 todo 应用

假设我们通过 FastAPI 集成 Pydantic 的优点,写一个 todo 应用的接口实现 Todo 应用的创建和查看功能,文件目录结构如下:



首先,我们通过 Pydantic 新建 todo 应用的 model.py:


from pydantic import BaseModel, StrictInt

class Todo(BaseModel): id: StrictInt item: str
复制代码


先简单定义了两个字段:


  • id:数字类型,作为唯一标识

  • item: 字符串类型


然后新建路由文件夹 router,在其中建立一个 todo_router.py 文件,写入如下代码:


from fastapi import APIRouterfrom models.model import Todo
todo_router = APIRouter()
todo_list = []
@todo_router.post("/todo")async def add_todo(todo: Todo) -> dict: todo_list.append(todo) return { "message": "Todo added successfully" }
@todo_router.get("/todo")async def retrieve_todos() -> dict: return { "todos": todo_list }
复制代码


回到 main.py:


from fastapi import FastAPI
from routers.todo_router import todo_router # importing router
app = FastAPI() # create an app instance


@app.get('/') async def home() -> dict: return { "message": "Welcome to my Page"}
app.include_router(todo_router)
复制代码

验证 Pydantic 是否生效

执行命令如下:


$ uvicorn main:app --reload --port 8888INFO:     Will watch for changes in these directories: ['C:\\Users\\Wade\\Desktop\\FastAPI\\fastwebprojects']INFO:     Uvicorn running on http://127.0.0.1:8888 (Press CTRL+C to quit)INFO:     Started reloader process [22288] using StatReloadINFO:     Started server process [25008]INFO:     Waiting for application startup.INFO:     Application startup complete.
复制代码


另外打开一个终端,执行 GET 请求,得到空的 todo 列表:


$ curl -X 'GET' 'http://127.0.0.1:8888/todo' -H 'accept: applicaion/json'{"todos":[]}
复制代码


接着执行 POST 请求,如下:


curl -X POST http://127.0.0.1:8888/todo -H 'accept: application/json' -H 'Content-Type: application/json' -d '{}'{"detail":[{"loc":["body","id"],"msg":"field required","type":"value_error.missing"},{"loc":["body","item"],"msg":"field required","type":"value_error.missing"}]}
复制代码


如果我们传入一个空的数组,将会得到一串由 Pydantic 校验生成的 JSON 数据,格式化如下:


{  "detail": [    {      "loc": [        "body",        "id"      ],      "msg": "field required",      "type": "value_error.missing"    },    {      "loc": [        "body",        "item"      ],      "msg": "field required",      "type": "value_error.missing"    }  ]}
复制代码


该 JSON 数据提示我们 id 和 item 都是必须字段 "msg": "field required", 因此,我们更改一下 POST 请求,如下:


$ curl -X POST http://127.0.0.1:8888/todo -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"id": 1, "item": "write a todo project"}'    {"message":"Todo added successfully"}
复制代码


此时我们可以看到创建一个 todo 事项成功,返回了 {"message":"Todo added successfully"} !


再执行一次 curl 的 GET 请求,结果如下,可以看到刚刚创建成功的今日 todo—— item"write a todo project", id 值为 1:


$ curl -X 'GET' 'http://127.0.0.1:8888/todo' -H 'accept: applicaion/json'        {"todos":[{"id":1,"item":"write a todo project"}]}
复制代码


打开 http://127.0.0.1:8888/docs ,可以看到如下界面:



此处 Todo 就是我们刚刚定义的 Model 中限定的字段类型:


总结

本文介绍了 Pydantic 以及它的安装与工作方式, Pydantic 提供了自动的数据验证,提高了性能,并且支持复杂的数据结构,使得构建健壮和可维护的应用程序更加容易。虽然本文只是简单的校验数据的存在性,还有更多比如邮箱、密码格式等等, Pydantic 都会提供,希望本文抛砖引玉,让大家探索和学习 Pydantic 的更多功能。


希望本文能对你有所帮助,如果喜欢本文,可以点个关注.

下一篇文章见!宇宙古今无有穷期,一生不过须臾,当思奋争。


参考链接:


发布于: 2023-04-04阅读数: 227
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020-05-07 加入

🏆InfoQ写作平台-签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于外企开发,弹性不加班 热衷分享,执着于阅读写作,佛系不水文 同名公众号:《宇宙之一粟》

评论

发布
暂无评论
FastAPI 开发中数据校验利器 Pydantic 介绍与集成使用_Python_宇宙之一粟_InfoQ写作社区