FastAPI简介

FastAPI简介

  • 一、FastAPI简介
  • 二、FastAPI安装
    • 2.1 使用pip安装FastAPI
    • 2.2 FastAPI的demo
    • 2.3 FastAPI的程序结构
  • 三、装饰器请求方法
  • 四、用户请求
    • 4.1 路径参数
      • 4.1.1 单个路径参数
      • 4.1.2 多个路径参数
      • 4.1.3 固定路径和路径参数的冲突
    • 4.2 查询参数
    • 4.3 默认参数
    • 4.4 可选参数
  • 五、请求体
    • 5.1 关于请求体
    • 5.2 实现请求体
    • 5.3 关于Pydantic的BaseModel类
    • 5.4 关于Pydantic.Field

一、FastAPI简介

FastAPI源码
FastAPI官方中文文档
FastAPI官方文档

Pydantic官方文档

二、FastAPI安装

2.1 使用pip安装FastAPI

  • 安装FastAPI
pip install fastapi
  • 安装FastAPI依赖库
    FastAPI的依赖库包括 Uvicorn、Pydantic 和 Starlette 库
pip install uvicorn[standard]
pip install pydantic
pip install starlette

可以安装所有依赖库

pip3 install fastapi[all]
  • 验证安装成功
import fastapi
print(fastapi.__version__)

2.2 FastAPI的demo

创建main.py的文件:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

在命令行运行如下指令:

uvicorn main:app --reload

可以看到如下输出:

INFO:     Will watch for changes in these directories: ['/root']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [3531390] using WatchFiles
INFO:     Started server process [3531392]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

在本机浏览器中输入: http://127.0.0.1:8000
打印出:"message": "Hello World" ,则表示安装成功。
在这里插入图片描述

Uvicorn 启动信息

  • INFO: Will watch for changes in these directories: ['/root']
    表示 Uvicorn 将监视 /root 目录下的文件变化以触发自动重载。
    这意味着如果在这个目录下对 Python 文件进行了任何改动,Uvicorn 将会重启应用。
  • INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
    告知用户 Uvicorn 已经启动并在本地地址 http://127.0.0.1:8000 上监听请求。
    这意味着您可以访问此 URL 来测试您的 API。
  • INFO: Started reloader process [3531227] using WatchFiles
    说明 Uvicorn 使用 WatchFiles 方法启动了一个后台进程来监控文件系统的变化,以便能够及时响应文件更新并触发应用的重新加载。
  • INFO: Started server process [3531230]
    显示 Uvicorn 已经启动了一个新的子进程来处理 HTTP 请求。
  • INFO: Waiting for application startup. 和 INFO: Application startup complete.:
    这两条日志表明 FastAPI 应用正在启动,并且已经成功完成了启动过程,现在可以接收来自客户端的请求。
  • 综上所述,已经正确设置了开发环境,并且 FastAPI 应用程序正在正常运行。
    开发时,只要保持终端窗口打开并且不要关闭 Uvicorn 进程,每次对 main.py 或者其他被监控的文件做出更改,Uvicorn 都会自动重新加载应用,使得最新的代码变更立即生效。
    如果要停止服务,只需按 CTRL+C 即可终止 Uvicorn 进程。
    此外,请注意,在生产环境中部署时应避免使用 --reload 选项,因为这可能会导致不必要的资源消耗和稳定性问题9。

Uvicorn 命令详解

uvicorn main:app --reload 是一个用于启动 FastAPI 应用程序的命令行语句,它结合了 Uvicorn 服务器与 FastAPI 框架的功能。
作用就是使用 Uvicorn 启动位于 main.py 文件中的 FastAPI 应用,并且开启了热重载模式以便于开发过程中快速迭代和测试
这条命令中的各个部分具有特定的意义:

  • uvicorn:这是调用 Uvicorn ASGI(异步网关接口)服务器的命令。
  • main:app:这部分指定了要运行的应用程序。
    • main 表示 Python 模块的名字,通常是文件名为 main.py 的模块(即 main.py 文件去掉扩展名);
    • app 则是指在这个模块中定义的一个 FastAPI 实例对象的名字。
      例如,在 main.py 文件中有如下代码 app = FastAPI(),那么这里的 app 就是指这个 FastAPI 应用实例。
  • --reload:这是一个选项参数,表示开启热重载功能。
    • 当启用此选项时,Uvicorn 会在检测到代码发生更改后自动重启服务器。
    • 这对于开发环境非常有用,因为它可以确保开发者在修改代码后无需手动重启服务器即可看到最新的更改效果。
    • 值得注意的是,在生产环境中不应该使用 --reload 选项,因为这会消耗更多资源并且可能不如预期稳定。
  • 在非默认端口上使用热重载功能时,可以通过配置启动命令或修改配置文件来实现
    • 命令:uvicorn main:app --host 127.0.0.1 --port 9000 --reload
    • –host 参数指定了监听的 IP 地址
    • –port 参数则定义了监听的端口号
    • –reload 选项开启了热重载功能

2.3 FastAPI的程序结构

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)
  • Step1: 导包
 import uvicorn
from fastapi import FastAPI
  • Step2: 创建一个 FastAPI 实例,这个实例是应用程序的核心,所有的路由和配置都将围绕它进行
app = FastAPI()
  • Step3: 定义一个路径操作函数 root,它被装饰器 @app.get("/") 标记为根路径(/)的处理器
    这意味着当用户访问应用程序的根 URL 时,FastAPI 将调用此函数来处理请求。
    • 返回一个 JSON 响应,包含消息 “Hello World”。由于 FastAPI 支持异步定义,
    • 使用 async def 可以更好地利用其异步特性,从而提高性能。
@app.get("/")
async def root():
    return {"message": "Hello World"}
  • Step4: 检查当前模块是否作为主程序运行。如果是,则执行以下代码块。
    调用 uvicorn.run() 函数启动 Uvicorn 服务器,提供必要的参数如应用对象 (app)、主机地址 (host) 和端口 (port)
    • 参数 host="127.0.0.1" 表示服务器只接受来自本地计算机的连接;
    • 参数 port=8000 表示服务器将在端口 8000 上监听 HTTP 请求。
if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)
  • Step5: 查看运行结果
    在本机浏览器中输入: http://127.0.0.1:8000
    打印出:"message": "Hello World" ,则表示安装成功。
    在这里插入图片描述

装饰器函数的返回值

  • 返回 Python 数据类型
    当路由函数返回一个简单的 Python 数据类型时,例如字符串、整数或布尔值,FastAPI 会自动将它们转换成相应的 JSON 格式,并设置正确的 Content-Type 头信息为 application/json。
    这意味着如果返回的是字符串 “hello fastapi”,它将被当作 JSON 字符串返回给客户端。
  • 返回字典或列表
    返回字典或列表时,FastAPI 同样会将其序列化为 JSON。
    • 对于字典而言,键必须是字符串,而值可以是任何能被 JSON 序列化的数据类型;
    • 对于列表,则其元素也需满足同样的条件。
  • 返回 Pydantic 模型
    Pydantic 是一个用于数据验证及设定的库,它允许定义具有类型注解的数据模型。
    当从 FastAPI 路由中返回 Pydantic 模型实例时,框架会自动调用 jsonable_encoder 函数来处理复杂的数据类型(如日期时间、UUID 等),确保它们能够正确地被 JSON 序列化。
    这不仅简化了开发者的代码编写过程,还保证了 API 输出的一致性和准确性。
  • 使用自定义 JSONResponse
    有时候,开发者可能希望对响应进行更细粒度的控制,比如添加自定义头部或者设置不同的状态码。
    这时就可以使用 JSONResponse 类来构建响应对象。JSONResponse 继承自 Response 类,允许指定额外的参数如 status_code、headers 和 media_type 来定制响应行为

三、装饰器请求方法

装饰器包含8中HTTP请求方法:

  • @app.get()
    用于从服务器获取信息。
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    return {"item_id": item_id}

# 如果访问 http://127.0.0.1:8000/items/42
# 运行结果:
# {
#   "item_id": 42
# }

在这里插入图片描述

  • @app.post()
    用于向指定资源提交数据,常用于创建新资源。
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.post("/items/")
async def create_item(item: Item):
    return item

# 如果发送 POST 请求到 http://127.0.0.1:8000/items/
# 并且请求体是 {"name": "Foo", "description": "A very nice Item", "price": 35.4}
# 运行结果:
# {
#   "name": "Foo",
#   "description": "A very nice Item",
#   "price": 35.4,
#   "tax": null
# }

在这里插入图片描述

  • @app.delete()
    用于删除指定资源。
if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

在这里插入图片描述

  • @app.put()
    用于更新整个资源。
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}

# 如果发送 PUT 请求到 http://127.0.0.1:8000/items/789
# 并且请求体是 {"name": "Updated Foo", "price": 35.4}
# 运行结果:
# {
#   "item_id": 789,
#   "name": "Updated Foo",
#   "description": null,
#   "price": 35.4,
#   "tax": null
# }

在这里插入图片描述

  • @app.head()
    与 GET 类似,但不返回消息体,只用来获取响应头。
from fastapi import FastAPI

app = FastAPI()

@app.head("/items/")
async def head_items():
    # 只返回头部,没有主体内容
    pass

# 如果发送 HEAD 请求到 http://127.0.0.1:8000/items/
# 运行结果:
# HTTP响应头,例如:
# Content-Length: 0
# Content-Type: application/json
# Date: Sat, 14 Dec 2024 17:54:00 GMT
# Server: uvicorn
  • @app.patch()
    用于对资源进行部分更新。
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class ItemUpdate(BaseModel):
    name: str | None = None
    description: str | None = None
    price: float | None = None
    tax: float | None = None

@app.patch("/items/{item_id}")
async def patch_item(item_id: int, item_update: ItemUpdate):
    return {"item_id": item_id, **item_update.dict(exclude_unset=True)}

# 如果发送 PATCH 请求到 http://127.0.0.1:8000/items/567
# 并且请求体是 {"name": "Patched Foo"}
# 运行结果:
# {
#   "item_id": 567,
#   "name": "Patched Foo"
# }

在这里插入图片描述

  • @app.trace()
    用于追踪路径,通常由客户端发送请求,服务器将请求作为实体返回。
from fastapi import FastAPI

app = FastAPI()

@app.trace("/trace")
async def trace_endpoint():
    # 追踪请求
    pass

# 如果发送 TRACE 请求到 http://127.0.0.1:8000/trace
# 运行结果:
# 返回客户端发送的原始请求
  • @app.options()
    用于描述通信选项,即客户端可以对资源执行哪些方法。
from fastapi import FastAPI

app = FastAPI()

@app.options("/items/")
async def options_items():
    return {"Allow": "GET, POST, PUT, DELETE, PATCH, OPTIONS"}

# 如果发送 OPTIONS 请求到 http://127.0.0.1:8000/items/
# 运行结果:
# {
#   "Allow": "GET, POST, PUT, DELETE, PATCH, OPTIONS"
# }

在这里插入图片描述

四、用户请求

FastAPI允许开发人员通过路径参数或路径变量从API的端点URL中获取请求数据。
(路径参数或路径变量使URL呈现一些动态变化。)

路径参数包含一个值,该值成为由花括号{}指示的URL的一部分。
在URL中设置这些路径参数后,FastAPI要求通过应用类型提示来声明这些参数。

4.1 路径参数

4.1.1 单个路径参数

以下delete_username()服务是一个DELETE API方法,它使用username路径参数搜索用户登录记录以进行删除:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


@app.delete("/login/remove/{username}")
async def delete_username(username: str):
    if username == None:
        return {"message": "invalid username"}
    else:
        return {"message": "deleted username"}

# 如果发送 DELETE 请求到 http://127.0.0.1:8000/login/remove/Jack
# 运行结果:
# {
#     "message": "deleted username"
# }

在这里插入图片描述

4.1.2 多个路径参数

如果最左边的变量比最右边的变量更有可能填充值,则可以接受多个路径参数。
换句话说,最左边的变量的重要性将使得其处理比最右边的路径变量更相关,也更正确。
应用此标准是为了确保端点URL不会看起来像其他URL,防止产生冲突和混淆。

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/login/{username}/{password}")
async def combine_parameters(username: str, password: int):
    # 定义有效的用户名和密码
    valid_username = "Jack"
    valid_password = 123456
    
    # 检查提供的用户名和密码是否匹配预定义的有效值
    if username == valid_username and password == valid_password:
        combined_result = f"username is {username}, and password is {password}"
        return {"message": combined_result}
    else:
        # 如果提供的用户名或密码不正确,则抛出一个HTTP异常
        raise HTTPException(status_code=401, detail="Invalid username or password")
# 如果发送 DELETE 请求到 http://127.0.0.1:8000/login/Jack/123456
# 运行结果:
# {
#     "message": "username is Jack, and password is 123456"
# }

在这里插入图片描述

4.1.3 固定路径和路径参数的冲突

FastAPI对属于基本路径或具有不同子目录的顶级域路径的端点URL不友好。
当我们动态URL模式在分配特定路径变量时,看起来与其他固定端点URL相同时,就会发生这种情况。
这些固定URL在这些动态URL之后依次实现。

以下服务就是一个示例:

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/login/{username}/{password}")
async def combine_parameters(username: str, password: str):
    # 定义有效的用户名和密码
    valid_username = "Jack"
    valid_password = "123456"
    
    # 检查提供的用户名和密码是否匹配预定义的有效值
    if username == valid_username and password == valid_password:
        combined_result = f"username is {username}, and password is {password}"
        return {"message": combined_result}
    else:
        # 如果提供的用户名或密码不正确,则抛出一个HTTP异常
        raise HTTPException(status_code=401, detail="Invalid username or password")
        
@app.get("/login/detail/info")
async def login_info():
    return {"message": "username and password are needed"}
# 如果发送 DELETE 请求到 http://127.0.0.1:8000/login/detail/info
# 运行结果:
# {
#    "message": "username and password are needed"
# }

理论上,我们期望的输出如下:

# 如果发送 DELETE 请求到 http://127.0.0.1:8000/login/detail/info
# 运行结果:
# {
#    "message": "username and password are needed"
# }

实际得到的输出:
在这里插入图片描述
分析原因:
访问的url是http://127.0.0.1:8000/login/detail/info
实际访问的url是http://127.0.0.1:8000/login/{detail}/{info}
也就是说,固定路径的details和info路径目录,被视为username和password参数值。

解决办法:
首先应声明所有固定路径,然后再声明带有路径参数的动态端点URL。
上述示例中的login_info()服务应该在login_with_token()之前声明。

修改后的代码:

from fastapi import FastAPI, HTTPException

app = FastAPI()

        
@app.get("/login/detail/info")
async def login_info():
    return {"message": "username and password are needed"}
    
    
@app.get("/login/{username}/{password}")
async def combine_parameters(username: str, password: str):
    # 定义有效的用户名和密码
    valid_username = "Jack"
    valid_password = "123456"
    
    # 检查提供的用户名和密码是否匹配预定义的有效值
    if username == valid_username and password == valid_password:
        combined_result = f"username is {username}, and password is {password}"
        return {"message": combined_result}
    else:
        # 如果提供的用户名或密码不正确,则抛出一个HTTP异常
        raise HTTPException(status_code=401, detail="Invalid username or password"

运行结果和预期一致:
在这里插入图片描述

4.2 查询参数

查询参数是在端点URL结束后提供的键值对(key-value pair), 用问号?表示。
就像路径参数一样,它也保存请求数据,所有查询参数也在服务方法中声明。
API服务可以管理一系列由&分割的查询参数。

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/login/")
async def login(username: str, password: str):
    # 定义有效的用户名和密码
    valid_username = "Jack"
    valid_password = "123456"
    
    # 检查提供的用户名和密码是否匹配预定义的有效值
    if username == valid_username and password == valid_password:
        combined_result = f"username is {username}, and password is {password}"
        return {"message": combined_result}
    else:
        return {"message": error}

访问url:http://127.0.0.1:8000/login/?username=Jack&password=123456
在这里插入图片描述
该login服务使用username和password作为str类型的查询参数。

4.3 默认参数

API服务的查看参数和路径参数,都不是固定参数,可以为它们指定默认值,避免出现验证错误消息。
根据要求,分配的默认值通常是

  • 数字类型的0
  • 布尔类型的False
  • 字符串类型的空字符串
  • List类型的空列表
  • Dict类型的空字典
from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/login/")
async def login(username: str="Jack", password: str="123456"):
    # 定义有效的用户名和密码
    valid_username = "Jack"
    valid_password = "123456"
    
    # 检查提供的用户名和密码是否匹配预定义的有效值
    if username == valid_username and password == valid_password:
        combined_result = f"username is {username}, and password is {password}"
        return {"message": combined_result}
    else:
        return {"message": error}

# 如果发送 DELETE 请求到 http://127.0.0.1:8000/login
# 由于路径参数username和password有默认值,所以运行结果:
# {
#    "message": "username is Jack, and password is 123456"
# }

4.4 可选参数

如果API服务的路径不一定需要由用户提供,可以将这些路径或参数设置为可选参数。

要声明可选参数,需要从typeing模块中导入Optional类型,然后使用它来设置参数。
它应该使用方括号[]包装参数的假定数据类型,并且如果需要可以具有任何默认值。

from fastapi import FastAPI, HTTPException
from typing import Optional

app = FastAPI()

@app.get("/login/")
async def login(username: str, password: Optional[str] = None):
    # 定义有效的用户名
    valid_username = "Jack"
    
    # 检查提供的用户名
    if username == valid_username:
        combined_result = f"username is {username}"
        return {"message": combined_result}
    else:
        return {"message": error}
# 如果发送 GET 请求到 http://127.0.0.1:8000/login/?username=Jack
# 由于路径参数username和password有默认值,所以运行结果:
# {
#    "message": "username is Jack"
# }

在这里插入图片描述

五、请求体

5.1 关于请求体

将数据从客户端(例如浏览器)发送到API时,可以将其作为 “请求体” 发送。

  • 请求体是客户端发送到的API服务的数据。
  • 响应体是API服务发送给客户端的数据。

API几乎总是必须发送一个响应体,但是客户端并不需要一直发送请求体。

定义请求体,需要使用 Pydantic 模型。注意以下几点

  • 不能通过GET请求发送请求体
  • 发送请求体数据,必须使用以下几种方法之一:POST(最常见)、PUT、DELETE、PATCH

5.2 实现请求体

  • Setp1:从pydantic中导入BaseModel
from pydantic import BaseModel
  • Setp2:创建它的子类以利用所有属性和行为
  • Setp3:将模型定义为参数

5.3 关于Pydantic的BaseModel类

什么是 Pydantic 的 BaseModel?
Pydantic 是一个 Python 库,它帮助开发者确保他们的应用程序接收到的数据是正确的。
它通过使用 Python 的类型提示(type hints)来自动验证传入的数据是否符合预期的格式和类型。
BaseModelPydantic 提供的一个类,所有的数据模型都是从BaseModel类继承下来的

为什么需要Pydantic 的 BaseModel?

如何使用Pydantic 的 BaseModel?
下面的代码示例展示了如何使用 Pydantic 来定义一个数据模型,并通过该模型对输入的数据进行验证和解析

from datetime import datetime
from pydantic import BaseModel, PositiveInt

class User(BaseModel):
    id: int  
    name: str = 'John Doe'  
    signup_ts: datetime | None  
    tastes: dict[str, PositiveInt]  

external_data = {
    'id': 123,
    'signup_ts': '2019-06-01 12:22',  
    'tastes': {
        'wine': 9,
        b'cheese': 7,  
        'cabbage': '1',  
    },
}

user = User(**external_data)  

print(user.id)  
#> 123
print(user.model_dump())  
"""
{
    'id': 123, 
    'name': 'John Doe',
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},
}
  1. 定义 User 模型
from datetime import datetime
from pydantic import BaseModel, PositiveInt

class User(BaseModel):
    id: int  # 声明变量id是一个整型,必选字段
    name: str = 'John Doe'  # 声明变量name是str类型,默认值是'John Doe',必选字段
    signup_ts: datetime | None  # 声明变量signup_ts是一个时间类型,可选字段
    tastes: dict[str, PositiveInt]  # 声明变量tastes是字典类型,键是字符串类型的正整数,必选字段
  • 字段类型声明:在 User 类中,我们为每个字段指定了类型。
    • id 是必需的整数;
    • name 是字符串,默认值为 ‘John Doe’,意味着如果创建实例时没有提供这个字段,则会自动设置为默认值;
    • signup_ts 可以是 datetime 对象或 None,表示该字段是可选的;
    • tastes 是一个字典,键为字符串,值为正整数(PositiveInt),确保用户兴趣爱好评分不会为负数。
  • 类型注解与验证:
    • Pydantic 使用 Python 的类型注解来指定字段的数据类型。
    • 当创建 User 实例时,Pydantic 会根据这些注解自动验证传入的数据是否符合预期格式。
  1. 创建 User 实例并验证数据
external_data = {
    'id': 123,
    'signup_ts': '2019-06-01 12:22',  
    'tastes': {
        'wine': 9,
        b'cheese': 7,  
        'cabbage': '1',  
    },
}

user = User(**external_data)
  • 数据转换:即使某些字段的值不是严格意义上的正确类型
    例如,b'cheese' 是字节串而不是字符串,'1' 是字符串而不是整数),Pydantic 也会尝试将它们转换成正确的类型。
    对于 signup_ts 字段,Pydantic 能够识别 ISO8601 格式的日期时间字符串,并将其转换为 datetime 对象。
  • 错误处理:如果数据不符合预期类型或者违反了约束条件(如非正整数),Pydantic 将抛出 ValidationError 异常,并给出详细的错误信息。
    在这个例子中,所有的数据都被成功地验证和转换了。
  1. ”解包”(unpacking)操作符 **
    user = User(**external_data) 是一种非常常见的 Python 语法,它使用了所谓的“解包”(unpacking)操作符**
    这种用法允许我们将一个字典中的键值对作为关键字参数传递给函数或类的构造方法
    在这个例子中, User 是由 Pydantic 定义的一个数据模型类,而 external_data 是一个包含键值对的字典,这些键名与 User 类定义的字段名称相匹配。
  • external_data 字典
    这是一个包含用户信息的字典,其中键对应于 User 模型类中的字段名,值则是相应的数据。

  • ** 解包操作符
    通过在字典前加上双星号 **,Python 会将字典里的每个键值对展开成单独的关键字参数,并传递给 User 类的构造函数。
    因此,上面的例子等价于如下代码:

user = User(id=123, signup_ts='2019-06-01 12:22', tastes={'wine': 9, 'cheese': 7, 'cabbage': '1'})
  1. 输出结果
print(user.id)  
#> 123
print(user.model_dump())  
"""
{
    'id': 123,
    'name': 'John Doe',
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},
}
"""
  • 访问属性:一旦创建了 User 实例,就可以像普通 Python 对象一样访问其属性。
    这里打印了用户的 ID 和整个模型的字典表示形式。
    注意,在最终输出的结果中,signup_ts 已经被正确解析为了 datetime 对象,而 tastes 中的键也已经被统一成了字符串类型,且所有值都被转换为了正整数。
  1. 验证错误
 # continuing the above example...

from datetime import datetime
from pydantic import BaseModel, PositiveInt, ValidationError


class User(BaseModel):
    id: int
    name: str = 'John Doe'
    signup_ts: datetime | None
    tastes: dict[str, PositiveInt]


external_data = {'id': 'not an int', 'tastes': {}}  

try:
    User(**external_data)  
except ValidationError as e:
    print(e.errors())
    """
    [
        {
            'type': 'int_parsing',
            'loc': ('id',),
            'msg': 'Input should be a valid integer, unable to parse string as an integer',
            'input': 'not an int',
            'url': 'https://errors.pydantic.dev/2/v/int_parsing',
        },
        {
            'type': 'missing',
            'loc': ('signup_ts',),
            'msg': 'Field required',
            'input': {'id': 'not an int', 'tastes': {}},
            'url': 'https://errors.pydantic.dev/2/v/missing',
        },
    ]
    """

如果验证失败,Pydantic 将引发错误并详细说明错误原因:

external_data 包含了两个可能导致验证失败的问题:

  • id 字段的值 'not an int' 不是有效的整数。
    id 字段要求的是一个整数值,但是给定的是一个无法解析成整数的字符串 'not an int'
    因此,Pydantic 抛出了一个类型为 int_parsing 的错误,表明输入不是有效的整数,并且无法将字符串解析为整数

  • signup_ts 字段没有提供,默认情况下它是必需的,除非你在模型配置中指定了它可以为 None 或者设置了默认值。
    signup_ts 字段是必需的,但在 external_data 中并没有提供相应的值。
    由于它既不是一个有效的 `datetime`` 对象也不是 None(假设允许为空),所以 Pydantic 认为此字段缺失,从而抛出了 missing 类型的错误。

5.4 关于Pydantic.Field

  • 什么是 Pydantic.Field?
    Pydantic Field 是一个非常强大的工具,它允许开发者为数据模型中的字段添加额外的验证和元数据信息
    通过使用 Field,我们可以更精细地控制数据模型的行为,确保数据的有效性和一致性。

  • 为什么需要 Pydantic.Field?
    在定义数据模型时,有时仅靠类型注解并不能完全表达我们对字段的所有要求。
    例如,我们可能希望限制字符串的最大长度、指定数值的取值范围或为字段提供描述性文本。
    此时,Field 就派上了用场。
    它可以用来设置字段的默认值、定义必填项与可选项、设定最大最小值等约束条件,以及为字段添加描述信息,这些都对于生成文档和支持API开发非常重要。

  • 如何使用 Pydantic.Field?
    要使用 Field,首先需要从 pydantic 中导入它。
    然后,在定义模型类时,可以通过将 Field 函数作为字段类型的默认值来应用这些额外的信息和约束。
    下面是一个简单的例子:

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str
    description: str = Field(None, title="The description of the item", max_length=10)
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: float = None

在这个例子中:
- description 字段被标记为可选,并且设置了最大长度为 10。
- price 字段是必填项(用省略号 … 表示),并且指定了它的值必须大于零。
- 当创建 Item 实例时,如果提供了超出规定的 description 长度或者不符合 price 约束的数据,则会触发验证错误。

  • Field 的参数说明?
    Field 提供了一系列参数用于定制字段行为,包括但不限于以下几种:
    • default : 定义字段的默认值;如果未提供该值,默认为 None。
    • alias : 定义字段的别名,这在处理不符合 Python 变量命名规则的字段名时特别有用。
    • title : 为字段定义标题,这对生成文档很有帮助。
    • description : 提供字段的描述信息,同样有助于生成详细的 API 文档。
    • min_length max_length : 对于字符串类型字段,可以定义其最小和最大长度。
    • gt, ge, lt, le : 分别表示数值类型的字段应大于、大于等于、小于、小于等于某个特定值。
    • 其他如 regex 正则表达式验证、allow_mutation 是否允许修改字段值等高级选项也都可以通过 Field 来配置。
    • 此外, Field 还支持传递任意关键字参数到 JSON Schema 中,这意味着你可以根据需要灵活地扩展字段的功能。
      例如, examples 参数可以直接影响生成的 OpenAPI 文档中的示例值。

总之, Field 不仅仅是用来替代简单类型注解的一种方式,它更是 Pydantic 框架中实现复杂数据验证逻辑不可或缺的一部分。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/936700.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于Postgresql旧版本安装

抛出问题 局点项目现场,要求对如下三类资产做安全加固,需要在公司侧搭建测试验证环境,故有此篇。 bclinux 8.2 tomcat-8.5.59 postgrel -11 随着PG迭代,老旧版本仅提供有限维护。如果想安装老版本可能就要费劲儿一些。现在&…

金融信息分析基础(1)

1.金融数据 金融数据分为:交易数据(低频数据,高频数据,超高频数据),报表数据(财务报表,研报),金融社交媒体数据 低频数据: 以日、周、月、季、年…

C# 网络编程--关于UDP 通信(二)

UDP (User Datagram Protocol) 是一种无连接的传输层协议,主要用于支持数据报文的传输。它的主要特点包括简单、高效、不保证可靠性和顺序。 1.UDP协议基本概念 1.udp基于IP的简单的协议,不可靠的协议 2.优点:简单、 轻量化、 传输速度高、…

1 汇编语言

课程概要 人与人沟通需要使用到语言,人与计算机沟通也需要一种语言进行,你要跟计算机进行沟通,必须要使用计算机可以识别的语言,这种语言我们称之为机器语言,也就是0和1,二进制。 但对于人来说机器语言&a…

每天40分玩转Django:简介和环境搭建

Django简介和环境搭建 一、课程概述 学习项目具体内容预计用时Django概念Django框架介绍、MVC/MTV模式、Django特点60分钟环境搭建Python安装、pip配置、Django安装、IDE选择45分钟创建项目项目结构、基本配置、运行测试75分钟实战练习创建个人博客项目框架60分钟 二、Djang…

AI学习记录 - 依据 minimind 项目入门

想学习AI,还是需要从头到尾跑一边流程,最近看到这个项目 minimind, 我也记录下学习到的东西,需要结合项目的readme看。 1、github链接 https://github.com/jingyaogong/minimind?tabreadme-ov-file 2、硬件环境:英伟达4070ti …

对象键值对的修改

一:一个对象,过滤掉键对应的值是空数组的键,保留值不是空数组的键值对 const obj {a: [1, 2, 3],b: [],c: [4, 5],d: [],e: [6] };// 过滤掉值为空数组的键值对 const filteredObj Object.fromEntries(Object.entries(obj).filter(([key, v…

Java基础知识(四) -- 面向对象(中)

1.封装 1.1 概述 面向对象编程语言是对客观世界的模拟,客观世界里每一个事物的内部信息都是隐藏在对象内部的,外界无法直接操作和修改,只能通过指定的方式进行访问和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其…

02. Docker:安装和操作

目录 一、Docker的安装方式 1、实验环境准备 1.1 关闭防火墙 1.2 可以访问网络 1.3 配置yum源 2、yum安装docker 2.1 安装docker服务 2.2 配置镜像加速 2.3 启动docker服务 3、二进制安装docker 3.1 下载或上传安装包并解压 3.2 配置使用systemctl管理 3.3 配置镜像…

【人工智能】OpenAI O1模型:超越GPT-4的长上下文RAG性能详解与优化指南

在人工智能(AI)领域,长上下文生成与检索(RAG) 已成为提升自然语言处理(NLP)模型性能的关键技术之一。随着数据规模与应用场景的不断扩展,如何高效地处理海量上下文信息,成…

#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍01

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…

华为FreeBuds Pro 4丢了如何找回?(附查找功能使用方法)

华为FreeBuds Pro 4查找到底怎么用?华为FreeBuds Pro 4有星闪精确查找和离线查找,离线查找功能涵盖播放铃声、导航定位、星闪精确查找、上线通知、丢失模式、遗落提醒等。星闪精确查找是离线查找的子功能,当前仅华为FreeBuds Pro 4充电盒支持…

Python爬虫之Scrapy框架基础入门

Scrapy 是一个用于Python的开源网络爬虫框架,它为编写网络爬虫来抓取网站数据并提取结构化信息提供了一种高效的方法。Scrapy可以用于各种目的的数据抓取,如数据挖掘、监控和自动化测试等。 【1】安装 pip install scrapy安装成功如下所示:…

【电子元器件】电感基础知识

本文章是笔者整理的备忘笔记。希望在帮助自己温习避免遗忘的同时,也能帮助其他需要参考的朋友。如有谬误,欢迎大家进行指正。 一、 电感的基本工作原理 1. 电感的基本工作原理如下: (1) 当线圈中有电流通过时&#…

OpenGL ES详解——多个纹理实现混叠显示

目录 一、获取图片纹理数据 二、着色器编写 1. 顶点着色器 2. 片元着色器 三、绑定和绘制纹理 1. 绑定纹理 2. 绘制纹理 四、源码下载 一、获取图片纹理数据 获取图片纹理数据代码如下: //获取图片1纹理数据 mTextureId loadTexture(mContext, R.mipmap.…

C#,在 C# 语言中将 LaTeX 转换为 PNG 或 JPG 图像

在 C 语言中将 LaTeX 转换为 PNG 或 JPG 图像# 12月 28, 2021 2 分钟 法尔汉拉扎 在 C 语言中将 TeX 转换为 PNG JPG 图像# TeX 格式用于处理技术和科学文件。它通常用于交流或发布此类文档。在某些情况下,您可能需要将 TeX 文件渲染为 PNG 或 JPG 等图像…

顺序表(数据结构初阶)

文章目录 顺序表一:线性表1.1概念: 二:顺序表2.1概念与结构:2.2分类:2.2.1静态顺序表2.2.2动态顺序表 2.3动态顺序表的实现声明(初始化)检查空间容量尾插头插尾删头删查找指定位置之前插入数据指…

活动报名:Voice Agent 开发者分享会丨RTE Meetup

引入 voice agent 的口语学习应用 Speak 估值已达 10 亿美元 Voice Agent 开发者分享会 一同探索语音驱动的下一代人机交互界面,一场 voice agent builder 的小规模深度交流会。 RTE Meetup 迎来第六期!12 月 15 日(周日)上午&…

STM32 CubeMx HAL库 独立看门狗IWDG配置使用

看门狗这里我就不多介绍了,能搜到这篇文章说明你了解 总之就是一个单片机重启程序,设定好超时时间,在超时时间内没有喂狗,单片机就会复位 主要应用在单片机异常重启方面,比如程序跑飞(注意程序跑飞时你就…

pdb调试器详解

文章目录 1. 启动 pdb 调试器1.1 在代码中插入断点1.2 使用命令行直接调试脚本 2. 常用调试命令2.1 基本命令2.2 高级命令2.3 断点操作 3. 调试过程示例4. 调试技巧4.1 条件断点4.2 自动启用调试4.2.1 运行程序时指定 -m pdb4.2.2在代码中启用 pdb.post_mortem4.2.3 使用 sys.e…