FastAPI框架入门教程

文章目录

  • 🟢 FastApi
      • FastAPI 的核心优势
      • 为什么选择 FastAPI?
      • CGI/WSGI/ASGI了解
  • 一、FastAPI环境搭建
      • 创建虚拟环境
      • 安装 FastAPI 及其依赖
  • 二、FastAPI第一个 API与启动项目
      • 启动项目
      • 访问文档
  • 三、用AI生成API接口
      • 提示示例
      • 注意事项
      • AI的生成的问题
  • 四、FastAPI路径参数
  • 五、 FastAPI查询参数
  • 五、 FastAPI请求体
      • 定义模型
  • 六、FastAPI请求参数类型验证_原生类型注解
  • 七、FastAPI请求参数验证_Query方式
        1. 基础验证
        1. 长度限制
        1. 正则表达式验证
        1. 默认值与必填项
        1. 数值范围验证
        1. 多值参数(列表)
        1. 别名与元数据
        1. 弃用参数
  • 八、FastAPI请求参数验证_Path方式
        1. 基础类型验证
        1. 必填与可选
        1. 数值范围验证
        1. 字符串格式验证
        1. 枚举值限制
        1. 元数据与别名
        1. 自定义验证器
  • 九、FastAPI请求参数验证_Field方式
        1. 基础类型与默认值
        1. 数值范围验证
        1. 字符串格式验证
        1. 元数据与文档增强
        1. 复杂类型与嵌套验证
        1. 自定义验证器
        1. 别名与字段映射
        1. 高级约束
        1. 动态默认值
  • 十、 FastAPI表单数据
  • 十一、 FastAPI异步处理
        • 异步 (async def)
        • 非异步 (def)
  • 十二、 FastAPI文件上传
        1. 基础文件上传
        • 方式一:`bytes` 类型(适合小文件)
        • 方式二:`UploadFile` 类型(推荐)
        1. 多文件上传
        1. 文件保存到本地
        • 同步保存(小文件)
        • 异步保存(大文件优化)
        1. 文件验证
        • 类型校验
        1. 混合表单与文件上传
  • 十三、 FastAPI请求对象Request
        • 基础用法
  • 十四、FastAPI响应数据-JSON格式
      • 响应类型介绍
      • JSON 响应(80%+ 场景)
  • 十五、FastAPI响应数据-列表格式
      • 示例
  • 十六、 FastAPI响应数据-文件格式
      • 示例
  • 十七、 FastAPI响应数据-其它格式
      • 其它响应的格式
  • ✒️总结

🟢 FastApi

FastAPI 是一个现代、高性能的 Python Web 框架,用于构建 API。它基于 Starlette (异步 Web 框架)和 Pydantic (数据验证库),结合了异步编程和类型提示,兼顾开发效率与运行性能。
code仓库
文档https://fastapi.tiangolo.com
源码

主要功能特性:

  • 快速:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一。
  • 高效编码:提高功能开发速度约 200% 至 300%。
  • 更少 bug:减少约 40% 的人为(开发者)导致错误。
  • 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。
  • 简单:设计的易于使用和学习,阅读文档的时间更短。
  • 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。
  • 健壮:生产可用级别的代码。还有自动生成的交互式文档。
  • 自动处理碎片,以支持云计算层次的扩展。
  • 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema

FastAPI 的核心优势

高性能:

  • FastAPI 基于异步 I/O,性能接近 Node.js 和 Go。

  • 使用 Uvicorn(ASGI 服务器),支持高并发请求。

  • 性能对比(基于 TechEmpower 等基准测试,简化为每秒请求数):

    • FastAPI:~3000 请求/秒(异步,轻量)
    • Flask:~1000 请求/秒(同步,受 WSGI 限制)
    • Django:~800 请求/秒(同步,ORM 和中间件开销较大)

类型提示提升开发效率:

  • FastAPI 使用 Python 类型提示(通过 Pydantic)进行数据验证,减少手动校验代码。

  • 类型提示使代码更易读,IDE(如 VSCode)提供自动补全和错误提示。

  • 示例:定义一个带类型提示的 API 端点:

python 复制代码
  from fastapi import FastAPI
  from pydantic import BaseModel
  
  app = FastAPI()
  
  class Item(BaseModel):
      name: str
      price: float
      is_offer: bool = None
  
  @app.post("/items/")
  async def create_item(item: Item):
      return item

提示

上述代码自动验证请求体中的 name(字符串)、price(浮点数)和 is_offer(布尔值,可选),无需手动解析 JSON。

自动生成 API 文档

  • FastAPI 内置 Swagger UIReDoc,自动生成交互式 API 文档。
  • 开发者只需编写代码,文档即自动生成,减少维护成本。

异步支持

  • 支持 async/await 语法,适合高并发场景(如实时聊天、流处理)。
  • 比传统同步框架(如 Flask)更适合现代 Web 应用。

为什么选择 FastAPI?

  • 开发速度快:类型提示和自动文档减少重复工作。
  • 性能优异:异步架构支持高并发,适合生产环境。
  • 社区活跃:快速增长的生态,兼容 Starlette 和 Pydantic 的扩展。
  • 易于上手:Python 开发者只需掌握基本类型提示即可快速构建 API。

CGI/WSGI/ASGI了解

  • CGI 是最早的通用接口,解决服务器与动态内容生成程序的通信问题,但性能低下。
  • WSGI 针对 Python 生态优化,取代 CGI,成为 Python Web 开发的主流标准,专注于同步 Web 应用。
  • ASGI 是 WSGI 的升级,适应异步编程和现代 Web 需求(如 WebSocket、HTTP/2),兼容 WSGI 应用。

一、FastAPI环境搭建

创建虚拟环境

虚拟环境隔离项目依赖,避免全局环境冲突。以下使用conda工具:

  1. 创建虚拟环境:

    shell 复制代码
    conda create -n fastapi_env python=3.12
  2. 激活虚拟环境:

    shell 复制代码
    conda activate fastapi_env
  3. 退出虚拟环境

    python 复制代码
    conda deactivate

安装 FastAPI 及其依赖

  1. 在虚拟环境中安装 FastAPI:

    shell 复制代码
    pip install "fastapi[standard]"

    指定版本安装:

    shell 复制代码
    pip install fastapi==0.115.12
    pip install uvicorn==0.34.2

二、FastAPI第一个 API与启动项目

python 复制代码
# fast程序
from fastapi import FastAPI
import uvicorn

app = FastAPI()

# 创建服务
@app.get("/")
def read_root():
    return {"Hello": "World6666"}

# 启动服务
# 通过命令 uvicorn filename:appn --reload #启动服务,并自动重新加载代码内容
# 通过调试 fastapi dev filename.py  # 需要安装fastapi[standard]
# 通过py运行  python filename.py   # 要有运行项目的代码
if __name__ == '__main__':
     uvicorn.run('main_01:app',host='127.0.0.1',port=8000,reload=True)
     # uvicorn.run(app, host='127.0.0.1', port=8000)  # 不让加 reload
     # uvicorn file_name:object --reload

启动项目

  1. 运行python脚本

    python 复制代码
    uvicorn.run('main_01:app',host='0.0.0.0',port=8000,reload=True)
    uvicorn.run(app,host='0.0.0.0',port=8000,reload=True,debug=True)

    代码中要用服务器启动代码

  2. 服务器启动项目

    shell 复制代码
    uvicorn file_name:object --reload
  3. 调试命令

    shell 复制代码
    fastapi dev filename.py

访问文档

http://127.0.0.1:8000/docs

http://127.0.0.1:8000/redoc

三、用AI生成API接口

AI 工具可以通过自然语言提示生成代码。我们将模拟使用 AI 生成一个简单的 FastAPI 应用。

提示示例

向 AI 提供以下提示:

python 复制代码
# 编写一个FastAPI的HelloWorld程序,并加上注释

# 请为我生成一个 FastAPI 应用程序,功能:返回欢迎消息。

以下生成的代码

python 复制代码
# 导入FastAPI和相关模块
from fastapi import FastAPI
from typing import Optional  # 用于类型提示中的可选参数

# 创建FastAPI应用实例
# FastAPI() 是应用的入口点,所有配置和路由都将基于这个实例
app = FastAPI(
    title="HelloWorld API",  # API的标题,会在文档中显示
    description="一个简单的FastAPI HelloWorld示例",  # API的描述
    version="1.0.0"  # API的版本
)


# 定义根路由的GET请求处理函数
# 使用 @app.get("/") 装饰器将下面的函数注册为处理根路径GET请求的处理器
# 当用户访问 http://localhost:8000/ 时,这个函数会被调用
@app.get("/")
async def read_root():
    """
    根路径的GET请求处理器

    返回:
        dict: 包含欢迎信息的字典,会以JSON格式返回给客户端
    """
    return {"message": "Hello World!", "status": "success"}


# 定义带路径参数的路由
# {name} 是路径参数,可以在函数参数中获取
@app.get("/hello/{name}")
async def say_hello(name: str):
    """
    带路径参数的GET请求处理器

    参数:
        name (str): 用户的名称,从URL路径中获取

    返回:
        dict: 包含个性化问候信息的字典
    """
    return {"message": f"Hello, {name}!", "greeted_user": name}


# 定义带查询参数的路由
# 查询参数通过URL中的 ? 后指定,例如 /hello?name=Alice&title=Ms
@app.get("/hello/")
async def hello_with_query_params(name: str, title: Optional[str] = None):
    """
    带查询参数的GET请求处理器

    参数:
        name (str): 必需的用户名,通过查询参数传递
        title (Optional[str], 可选): 可选的称呼,默认为None

    返回:
        dict: 包含完整问候信息的字典
    """
    greeting = f"Hello, {title + ' ' if title else ''}{name}!"
    return {
        "message": greeting,
        "parameters": {"name": name, "title": title}
    }


# 定义POST请求处理器
@app.post("/message/")
async def create_message(message: str):
    """
    POST请求处理器示例

    参数:
        message (str): 通过请求体传递的消息内容

    返回:
        dict: 包含处理结果的字典
    """
    return {
        "status": "message_received",
        "your_message": message,
        "processed_at": "2024-01-01T12:00:00"  # 实际应用中应使用当前时间
    }


# 健康检查端点(常见于生产环境)
@app.get("/health")
async def health_check():
    """
    健康检查端点,用于监控API的运行状态

    返回:
        dict: 包含健康状态信息的字典
    """
    return {"status": "healthy", "service": "HelloWorld API"}


# 应用信息端点
@app.get("/info")
async def app_info():
    """
    返回应用的基本信息

    返回:
        dict: 包含应用信息的字典
    """
    return {
        "app_name": app.title,
        "description": app.description,
        "version": app.version,
        "docs_url": "/docs",  # FastAPI自动生成的交互式文档
        "redoc_url": "/redoc"  # FastAPI自动生成的ReDoc文档
    }


# 如果需要,可以添加启动时的初始化代码
# @app.on_event("startup")
# async def startup_event():
#     print("HelloWorld API 正在启动...")

# 这个条件确保当直接运行此文件时启动Uvicorn服务器
# 如果是被导入,则不会启动服务器
if __name__ == "__main__":
    import uvicorn

    # 启动Uvicorn服务器
    # uvicorn.run() 参数说明:
    # - app: FastAPI应用实例
    # - host: 绑定的主机地址,"0.0.0.0" 表示监听所有网络接口
    # - port: 绑定的端口号
    # - reload: 开发模式下启用热重载
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=8000,
        reload=True  # 开发时开启,生产环境应设为False
    )

注意事项

AI 生成的代码可能存在小错误(如缺少字段约束),需手动检查

AI的生成的问题

  1. AI生成代码的局限性
    • 缺乏上下文理解:AI生成的代码可能符合语法,但未必适配实际业务逻辑(如身份验证流程、数据库设计)。
    • 难以维护与调试:若只会"复制粘贴",遇到错误或需求变更时将束手无策。
    • 部署与运维盲区:AI通常不涉及服务器配置、性能优化、监控等生产环境关键环节。
  2. 核心能力的不可替代性
    • 架构设计思维:如何划分模块、设计REST API、管理依赖关系,需系统性训练。
    • 调试与问题定位:理解上下文机制、请求生命周期,才能快速排查异常。
    • 安全与性能意识:防止SQL注入、XSS攻击,或优化数据库查询,需人工介入设计。

四、FastAPI路径参数

FastAPI 支持使用 Python 字符串格式化语法声明路径参数变量):

python 复制代码
from fastapi import FastAPI

app = FastAPI()

@app.get("/args1/1")
def path_args1():
    return {"message": "id1"}

@app.get("/args2/{id}")
def path_args2():
    return {"message": "id2"}

@app.get("/args3/{id}")
def path_args3(id):
    '''函数的顺序就是路由的顺序'''
    return {"message": id}

@app.get("/args4/{id}")
def path_args4(id: int):
    '''函数的顺序就是路由的顺序'''
    return {"message": id}

@app.get("/args5/{id}/{name}")
def path_args5(id: str, name: str):
    '''函数的顺序就是路由的顺序'''
    return {"id": id, "name": name}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run('aaa:app', host="127.0.0.1", port=8000, reload=True)

五、 FastAPI查询参数

声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询 参数

查询字符串是键值对的集合,这些键值对位于 URL 的 ? 之后,以 & 分隔

例如:

URL 复制代码
http://127.0.0.1:8000/items/?page=1&limit=10
python 复制代码
from fastapi import FastAPI

app = FastAPI()

@app.get("/query1")
def page_limit(page, limit):
    return {"page": page, "limit": limit}

@app.get("/query2")
def page_limit2(page, limit=None):
    if limit:
        return {"page": page, "limit": limit}
    return {"page": page}

@app.get("/query3")
def page_limit3(page, limit, info: int):
    return {"page": page, "limit": limit, "info": info}

@app.get("/query4/{page}")
def page_limit4(page, limit, info: int):
    return {"page": page, "limit": limit, "info": info}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('aaa:app', host="127.0.0.1", port=8000, reload=True)

五、 FastAPI请求体

FastAPI 使用请求体从客户端(例如浏览器)向 API 发送数据。

请求体是客户端发送给 API 的数据。

发送数据使用 POST(最常用)、PUTDELETEPATCH 等操作。

定义模型

python 复制代码
from fastapi import FastAPI
from pydantic import BaseModel

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

app = FastAPI()

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

六、FastAPI请求参数类型验证_原生类型注解

原生类型注解

python 复制代码
# python 原生类型注解
from fastapi import FastAPI
from typing import Union,Optional,List
import uvicorn

app=FastAPI()


# 参数:类型
@app.get('/item1/{item_id}')
def read_item(item_id:int):
    return {'item_id':item_id}

@app.get('/item2/{item_id}')
def read_item2(item_id:str):
    return {'item_id':item_id}

#Union
@app.get('/item3/{item_id}')
def read_item3(item_id:Union[str,int]):
    # Union多选一str,int
    return {'item_id':item_id}

#Union
@app.get('/item3/{item_id}')
def read_item3(item_id:Union[str,int]):
    # Union多选一str,int
    return {'item_id':item_id}



@app.get('/item4/{item_id}')
def read_item4(item_id:Union[str,int]=100):
    '''这个不可用默认参数'''
    # Union多选一str,int
    return {'item_id':item_id}

#查询参数
@app.get('/item5')
def read_item5(item_id:Union[str,int]=100):
    return {'item_id':item_id}

# 整数或者null,非必传
@app.get('/item6')
def read_item6(item_id:Union[int,None]=None):
    return {'item_id':item_id}


# Optional
@app.get('/item7')
def read_item7(item_id:Optional[int]=None):
    '''这个Optional是Union[T,None]的缩写'''
    return {'item_id':item_id}

# Optional
@app.get('/item8')
def read_item8(item_ids:List):
    '''List接收列标数组,在查询参数可以用,路径参数不可用'''
    return {'item_id':item_ids}

if __name__=='__main__':
    uvicorn.run('main_type_Szj:app', host='127.0.0.1', port=8000, reload=True)

七、FastAPI请求参数验证_Query方式

FastAPI 提供了强大的 Query 参数验证功能,主要通过 Query 类和 Pydantic 模型实现。以下是详细的验证方式分类和示例:

python 复制代码
Query 属性
fastapi.param_functions def Query(default: Any = Undefined,
          *,
          default_factory: () -> Any | None = _Unset,
          alias: str | None = None,
          alias_priority: int | None = _Unset,
          validation_alias: str | None = None,
          serialization_alias: str | None = None,
          title: str | None = None,
          description: str | None = None,
          gt: float | None = None,
          ge: float | None = None,
          lt: float | None = None,
          le: float | None = None,
          min_length: int | None = None,
          max_length: int | None = None,
          pattern: str | None = None,
          regex: str | None = None,
          discriminator: str | None = None,
          strict: bool | None = _Unset,
          multiple_of: float | None = _Unset,
          allow_inf_nan: bool | None = _Unset,
          max_digits: int | None = _Unset,
          decimal_places: int | None = _Unset,
          examples: list | None = None,
          example: Any | None = _Unset,
          openapi_examples: dict[str, Example] | None = None,
          deprecated: str | bool | None = None,
          include_in_schema: bool = True,
          json_schema_extra: dict[str, Any] | None = None,
          **extra: Any) -> Any

1. 基础验证

  • 类型验证:自动将参数转换为声明类型(如 int、str)。

    python 复制代码
    from fastapi import FastAPI, Query
    app = FastAPI()
    
    @app.get("/items/")
    def read_items(q: str = Query(None)):  # 默认可选
        return {"q": q}

    若传入非字符串类型(如 /items/?q=123),FastAPI 会自动处理为字符串;

    若类型不匹配(如 int 参数传入非数字),返回 422 错误。


2. 长度限制

  • 字符串长度:通过 min_length和 max_length限制。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(None, min_length=3, max_length=50)):
        return {"q": q}

    若 q 长度不符合要求(如 q=ab),返回 422 错误。


3. 正则表达式验证

  • 格式匹配:使用 regex或者pattern参数。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(None, regex="^fixedquery$")):
        return {"q": q}

    仅接受完全匹配 fixedquery的输入。


4. 默认值与必填项

  • 默认值:通过 Query的第一个参数设置。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query("default")):
        return {"q": q}
  • 必填参数:使用 ...(省略号)标记。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(..., min_length=3)):
      return {"q": q}

    若未提供 q,返回 422 错误。


5. 数值范围验证

  • 数值限制:通过 gt(大于)、lt(小于)等参数。

    python 复制代码
    @app.get("/users/")
    def get_users(age: int = Query(..., gt=0, lt=100)):
      return {"age": age}

    若 age 不在 0-100 之间,返回错误。


6. 多值参数(列表)

  • 接收多个值:使用 List类型。

    python 复制代码
    from typing import List
    @app.get("/items/")
    def read_items(q: List[str] = Query(["default"])):
        return {"q": q}

    访问 /items/?q=foo&q=bar时,q值为 ["foo", "bar"]。


7. 别名与元数据

  • 别名:解决参数名冲突或提供友好名称。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(None, alias="item-query")):
        return {"q": q}

    需通过 /items/?item-query=foo 访问。

  • 描述信息:通过 description参数添加文档说明。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(None, description="搜索关键词")):
        return {"q": q}

8. 弃用参数

  • 标记弃用:通过 deprecated=True。

    python 复制代码
    @app.get("/items/")
    def read_items(q: str = Query(None, deprecated=True)):
        return {"q": q}

    在文档中标记该参数已弃用。

例子

python 复制代码
# 请求参数验证_query
from fastapi import FastAPI,Query
import uvicorn
app = FastAPI()

#Query参数 str验证类型,默认any
@app.get('/items1')
def read_items1(item_id:str=Query(None)):
    return {"item_id":item_id}

#Query参数 ...必传
@app.get('/items2')
def read_items2(item_id:str=Query(...)):
    return {"item_id":item_id}

#Query参数 min_length最小长度  max_length最大长度
@app.get('/items3')
def read_items3(item_id:str=Query(...,min_length=3,max_length=10)):
    return {"item_id":item_id}

#Query参数 限制内容大小 gt最小值 lt最大值
@app.get('/items4')
def read_items4(item_id:int=Query(...,gt=0,lt=100)):
    return {"item_id":item_id}


#Query参数 别名
@app.get('/items5')
def read_items5(item_id:int=Query(...,alias='id')):
    return {"item_id":item_id}


#Query参数 字段描述
@app.get('/items6')
def read_items6(item_id:int=Query(...,description="这个字段用用于筛选产品id")):
    return {"item_id":item_id}

#Query参数 弃用参数
@app.get('/items7')
def read_items7(item_id:int=Query(...,deprecated=True)):
    return {"item_id":item_id}

#Query参数 正则
@app.get('/items8')
def read_items8(item_id:str=Query(...,regex='^a\d{2}$')):
    return {"item_id":item_id}

#Query参数 正则
@app.get('/items9')
def read_items9(item_id:str=Query(...,pattern='^a\d{2}$')):
    return {"item_id":item_id}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('main_type_query:app', host="127.0.0.1", port=8001, reload=True)

八、FastAPI请求参数验证_Path方式

FastAPI 中的 Path 参数验证主要通过 Path 类和 Pydantic 模型实现,以下是详细的分类和示例:


1. 基础类型验证

  • 自动类型转换:FastAPI 根据类型注解自动转换路径参数类型,失败则返回 422 错误。

    python 复制代码
    from fastapi import FastAPI
    app = FastAPI()
    
    @app.get("/items/{item_id}")
    def read_item(item_id: int):  # 自动验证为整数
        return {"item_id": item_id}

    访问 /items/123返回 {"item_id": 123},但 /items/abc 会触发 422 错误。


2. 必填与可选

  • 强制必填:路径参数默认必填,即使设置 None也无效。

    python 复制代码
    @app.get("/items/{item_id}")
    def read_item(item_id: int = Path(...)):  # 显式声明必填
        return {"item_id": item_id}

    未提供 item_id时直接报错。


3. 数值范围验证

  • 范围限制:通过 gt(大于)、lt(小于)等参数限制数值范围。

    python 复制代码
    from fastapi import Path
    
    @app.get("/products/{product_id}")
    def get_product(product_id: int = Path(..., gt=1000, le=10000)):
        return {"product_id": product_id}

    仅接受 1000 < product_id ≤ 10000 的值。


4. 字符串格式验证

  • 正则表达式:使用 regex或 pattern校验字符串格式。

    python 复制代码
    @app.get("/credit-cards/{card_no}")
    def get_card(card_no: str = Path(..., regex=r"^[4-6]\d{15}$")):
        return {"card_no": card_no}

    仅接受以 4-6 开头且长度为 16 的数字字符串。


5. 枚举值限制

  • 预设值:通过 Enum类限制参数为特定值。

    python 复制代码
    from enum import Enum
    
    class ModelName(str, Enum):
        alexnet = "sxt"
        resnet = "itbaizhan"
    
    @app.get("/models/{model_name}")
    def get_model(model_name: ModelName):
        return {"model_name": model_name}

    仅接受 sxt或 itbaizhan


5. 元数据与别名

  • 描述与别名:添加文档说明或解决命名冲突。

    python 复制代码
    @app.get("/users/{user_id}")
    def read_user(user_id: int = Path(..., title="用户ID", alias="user-id")):
        return {"user_id": user_id}

    访问时需使用 /users/123,但文档中显示别名为 user-id。


6. 自定义验证器

  • 复杂逻辑

    python 复制代码
    from typing import Annotated
    from pydantic import BeforeValidator
    
    def validate(value):
        if not value.startswith('P-'):
            raise ValueError('必须以P-开头')
        return value
    
    
    # 创建带验证的类型别名
    Item = Annotated[str, BeforeValidator(validate)]
    
    
    @app.get('/items6/{item_id}')
    def read_item6(item_id: Item):
        return {'item_id': item_id}

    仅接受以 P-开头的编码。

九、FastAPI请求参数验证_Field方式

FastAPI 中的 Field 是 Pydantic 提供的核心验证工具,用于为模型字段添加校验规则和元数据。以下是其详细使用方式分类和示例:


1. 基础类型与默认值

  • 类型注解:通过 Python 类型提示声明字段类型,自动触发类型验证。

  • 默认值:通过 default 参数设置字段默认值。

    python 复制代码
    from pydantic import BaseModel, Field
    
    class User(BaseModel):
        name: str = Field(default="Anonymous")  # 默认值为 "Anonymous"
        age: int = Field(...)  # 必填字段

    若 age 未提供,FastAPI 返回 422 错误。


2. 数值范围验证

  • 范围限制:使用 gt(大于)、ge(大于等于)、lt(小于)、le(小于等于)。

    python 复制代码
    class Product(BaseModel):
        price: float = Field(..., gt=0, le=1000)  # 价格必须 >0 且 ≤1000

    若 price=0,触发验证错误。


3. 字符串格式验证

  • 长度限制min_lengthmax_length

  • 正则表达式:regex 或 pattern。

    python 复制代码
    class Account(BaseModel):
        username: str = Field(..., min_length=3, max_length=20)
        password: str = Field(..., regex=r"^[A-Za-z0-9@#$%^&+=]{8,}$")

    密码需至少 8 位且包含特定字符。


4. 元数据与文档增强

  • 标题与描述titledescription 用于生成 OpenAPI 文档。

  • 示例值:example 提供文档中的样例。

    python 复制代码
    class Item(BaseModel):
        name: str = Field(..., title="商品名称", description="必填,长度不超过50字符", example="手机")

    文档中显示字段说明和示例。


5. 复杂类型与嵌套验证

  • 列表验证min_itemsmax_items 限制列表长度。

  • 嵌套模型:结合其他 Pydantic 模型。

    python 复制代码
    class Order(BaseModel):
        items: list = Field(..., min_items=1)  # 至少1个商品
        address: dict = Field(..., description="配送地址")

    嵌套模型支持递归验证。


6. 自定义验证器

  • 字段级验证:使用

    python 复制代码
    @field_validator

    装饰器。

    python 复制代码
    from pydantic import field_validator
    
    class User(BaseModel):
        email: str
    
        @field_validator("email")
        def validate_email(cls, v):
            if "@" not in v:
                raise ValueError("邮箱格式无效")
            return v

    自定义逻辑优先于 Field 的内置规则。


7. 别名与字段映射

  • 别名:alias 解决 JSON 键名与 Python 变量名不一致问题。

    python 复制代码
    class Data(BaseModel):
        user_name: str = Field(..., alias="userName")  # 接收 JSON 中的 "userName"

    请求体需包含 {"userName": "John"}。


8. 高级约束

  • 枚举值:结合 Enum类限制字段取值。

    复制代码
    from enum import Enum
    
    class Status(str, Enum):
        ACTIVE = "active"
        INACTIVE = "inactive"
    
    class Task(BaseModel):
        status: Status = Field(default=Status.ACTIVE)

    仅接受 active或 inactive。


9. 动态默认值

  • 默认工厂:default_factory动态生成默认值。

    python 复制代码
    from uuid import uuid4
    
    class Document(BaseModel):
        id: str = Field(default_factory=lambda: str(uuid4()))

    每次创建模型时生成唯一 ID。

python 复制代码
# fiele验证
# 请求参数验证_query
from fastapi import FastAPI
from pydantic import BaseModel,Field
from pydantic import field_validator
from enum import Enum
app = FastAPI()

# Field 模块
class User(BaseModel):
    name:str =Field(default='初见') # default默认值
    age:str =Field(...) # 必填

# gt最小值  lt最大值  description说明
class Product(BaseModel):
    price:float=Field(...,gt=0,lt=1000,description='价格')

# min_length最小长度  max_length最大长度
# pattern正则
class Account(BaseModel):
    userName:str=Field(...,min_length=3,max_length=20)
    passWord:str=Field(...,pattern=r'\w{6,10}')

# title标题 description 说明  examples案例
class Items(BaseModel):
    name:str=Field(...,title='标题',description='标题必填',example='111')


class Email(BaseModel):
    email:str
    # 添加挑檐
    @field_validator('email')
    def email_vaildator(cls,v):
        if '@' not in v:
            raise ValueError('邮箱格式错误')
        return v

class Order(BaseModel):
    items:list=Field(...,max_length=10,min_length=1)
    address:str=Field(...,description='订单地址')

# 枚举
class Status(str,Enum):
    ACTIVE='active',
    INACTIVE='inactive'

class Task(BaseModel):
    status:str=Field(default=Status.ACTIVE)
@app.post('/users/')
def create_user(user:User):
    return user

@app.post('/product/')
def create_product(product:Product):
    return product


@app.post('/account/')
def create_account(account:Account):
    return account

@app.post('/item/')
def create_item(item:Items):
    return item


@app.post('/email/')
def create_email(email:Email):
    return email


@app.post('/order/')
def create_order(order:Order):
    return order


@app.post('/Task/')
def create_task(task:Task):
    return Task()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('mian_type_field:app', host="127.0.0.1", port=8001, reload=True)

十、 FastAPI表单数据

要使用表单,需预先安装python-multipart

shell 复制代码
pip install python-multipart

提示

自 FastAPI 版本 0.113.0 起支持此功能

python 复制代码
# 表单数据
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel

app = FastAPI()


@app.post("/login1")
def login1(username: str = Form(...), password: str = Form(...)):
    return {"username": username, "password": password}


class User1(BaseModel):
    username: str
    password: str


@app.post("/login2")
def login2(user: Annotated[User1, Form()]):
    return user


class User2(BaseModel):
    username: str = Form(...)
    password: str = Form(...)


@app.post("/login3")
def login3(user: Annotated[User2, Form()]):
    return user


if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app='main11:app', host='127.0.0.1', port=8000, reload=True)

十一、 FastAPI异步处理

在 FastAPI 中,异步(async)和非异步(同步)编程方式是其核心特性之一,它们在处理请求、性能以及并发能力上有着显著的区别。

异步 (async def)
  • 事件循环:异步代码运行在 Python 的异步事件循环(如 asyncio)中。事件循环负责协调多个协程(coroutines),在某个协程等待 I/O 操作(如数据库查询或 HTTP 请求)时,事件循环可以切换到其他协程执行。
  • 非阻塞:当一个异步函数调用 await,它会暂停执行,将控制权交回事件循环,允许其他任务运行,直到等待的操作完成。
  • 并发性:异步模式允许单个线程处理大量并发请求,特别适合高并发场景(如 Web 服务器处理大量客户端请求)。
非异步 (def)
  • 阻塞式执行:同步函数在调用时会完全占用线程,直到函数执行完成才会释放线程。
  • 线程池:在 FastAPI 中,同步函数由工作线程(worker threads)处理,Uvicorn(FastAPI 常用的 ASGI 服务器)会将同步函数放入线程池运行。
  • 并发限制:线程池的大小限制了同步函数的并发能力。如果线程池耗尽(例如,处理大量阻塞请求),新请求将排队等待。

示例

python 复制代码
from fastapi import FastAPI
import asyncio
import time

app = FastAPI()

# 异步 endpoint:模拟并发 I/O 操作
@app.get("/async")
async def async_endpoint():
    start = time.time()
    # 模拟 5 次异步 I/O 操作(并发执行)
    tasks = [asyncio.sleep(1) for _ in range(5)]
    await asyncio.gather(*tasks)
    end = time.time()
    return {"异步时长": f"{end - start:.2f}秒"}

# 同步 endpoint:模拟相同的 I/O 操作
@app.get("/sync")
def sync_endpoint():
    start = time.time()
    # 模拟 5 次同步 I/O 操作(顺序执行)
    for _ in range(5):
        time.sleep(1)
    end = time.time()
    return {"同步时长": f"{end - start:.2f}秒"}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run('app:app', host="127.0.0.1", port=8000, reload=True)

十二、 FastAPI文件上传

1. 基础文件上传

方式一:bytes 类型(适合小文件)
python 复制代码
from fastapi import FastAPI, File

app = FastAPI()

@app.post("/upload/")
def upload_file(file: bytes = File(...)):
    return {"file_size": len(file)}  # 文件内容直接加载到内存
方式二:UploadFile 类型(推荐)
python 复制代码
from fastapi import UploadFile

@app.post("/upload/")
def upload_file(file: UploadFile):
    contents = await file.read()  # 异步读取
    return {"filename": file.filename, "size": len(contents)}

优势

  • 自动处理内存和磁盘存储(超过阈值存磁盘)
  • 支持文件元数据(filename, content_type
  • 提供异步文件操作方法(read(), write()

2. 多文件上传

python 复制代码
from typing import List

@app.post("/batch-upload/")
def batch_upload(files: List[UploadFile] = File(...)):
    return {"count": len(files), "names": [f.filename for f in files]}

注意

  • 前端需设置 <input type="file" multiple>
  • 每个文件独立处理,避免内存溢出

3. 文件保存到本地

同步保存(小文件)
python 复制代码
@app.post("/save-file/")
async def save_file(file: UploadFile):
    with open(file.filename, "wb") as f:
        f.write(await file.read())  # 同步写入
    return {"status": "saved"}
异步保存(大文件优化)
python 复制代码
import aiofiles

@app.post("/save-large-file/")
async def save_large_file(file: UploadFile):
    async with aiofiles.open(file.filename, "wb") as f:
        while chunk := await file.read(1024 * 1024):  # 分块读取1MB
            await f.write(chunk)
    return {"status": "success"}

最佳实践

  • 使用 aiofiles 异步 IO 提升性能
  • 分块读取避免内存溢出

4. 文件验证

类型校验
python 复制代码
from fastapi import HTTPException

ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".gif"}

@app.post("/upload-image/")
def upload_image(file: UploadFile):
    # 校验文件类型
    ext = Path(file.filename).suffix.lower()
    if ext not in ALLOWED_EXTENSIONS:
        raise HTTPException(400, "不支持的文件扩展名")

    return {"filename": file.filename}

5. 混合表单与文件上传

python 复制代码
from fastapi import Form

@app.post("/submit-form/")
def submit_form(
    username: str = Form(...),
    avatar: UploadFile = File(...)
):
    return {"user": username, "avatar_size": avatar.size}

关键点

  • 必须使用 multipart/form-data 编码
  • 不能与 JSON 请求体(Body)混用

特点

  • 文件以二进制形式读取,适合小于 10MB 的文件
  • 内存占用高,大文件可能导致崩溃
python 复制代码
from fastapi import FastAPI,File,UploadFile,HTTPException,Form
from pathlib import Path
app = FastAPI()
import aiofiles
import os
import re
# aiofiles
# 小文件上传
@app.post('/upload1')
def upload_file1(file:bytes=File(...)):
    with open('./data/file.png','wb') as f:
        f.write(file)
    return{
        'msg':'文件上传成功'
    }

# 大文件上传 同步
@app.post('/upload2')
async def upload_file2(file:UploadFile):
    async with aiofiles.open(f'./data/{file.filename}','wb') as f:
        # chunk = await file.read(1024*1024)
        # while chunk:
        #     await f.write(chunk)
        #     chunk = await file.read(1024 * 1024)
        while chunk := await file.read(1024 * 1024):  # 分块读取1MB
            await f.write(chunk)
    return{
        'msg':'文件上传成功'
    }

@app.post('/batch-upload/')
def batchUpload(files:list[UploadFile]=File(...)):
    '''批量上传'''
    return {"count":len(files),'filename':[f.filename for f in files]}

#限制上传格式
ALLOWED_EXTENSIONS={'.png','.jpg','.jpeg','.gif'}

@app.post('/upload-image/')
def uploadImage(file:UploadFile):
    '''验证文件格式'''
    ext=Path(file.filename).suffix.lower()
    print('ext',ext)
    if ext not in ALLOWED_EXTENSIONS:
        raise HTTPException(400,'不支持的文件扩展名')
    # 保存文件的逻辑
    return  {'msg':'文件上传成功'}

# 表单+文件
@app.post('/submit-form')
def submitForm(uname:str=Form(...),file:UploadFile=File(...)):
    '''验证文件格式'''
    ext=Path(file.filename).suffix.lower()
    print('ext',ext)
    if ext not in ALLOWED_EXTENSIONS:
        raise HTTPException(400,'不支持的文件扩展名')
    # 保存文件的逻辑
    return  {'uname':uname,'msg':file.filename}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('main_UploadFile_01:app', host="127.0.0.1", port=8002, reload=True)

十三、 FastAPI请求对象Request

基础用法

通过注入Request对象可获取完整的请求信息景:

python 复制代码
# Request获取请求信息

from fastapi import FastAPI, Request

app = FastAPI()


@app.get('/client-info')
async def client_info(request: Request):
    return {
        "请求URL": request.url,
        "请求方法": request.method,
        "请求IP": request.client.host,
        "请求参数": request.query_params,
        "请求头": request.headers,
        # "请求json": await request.json(),
        "请求cookies": request.cookies,
        # "请求form": await request.form(),
        # "请求files": request.files,
        "请求path_params": request.path_params,

    }


if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app='main14:app', host='127.0.0.1', port=8000, reload=True)

十四、FastAPI响应数据-JSON格式

响应类型介绍

在企业级应用中,以下响应类型最为常见:

  1. JSON 响应:用于 RESTful API 的数据交互,占主导地位(如用户信息、订单、配置)。
  2. 列表响应:用于分页查询或批量数据返回(如商品列表、日志记录)。
  3. 文件响应:用于报表导出、文件下载(如 CSV、PDF)。
  4. 字符串响应:用于健康检查或简单状态反馈。
  5. HTML 响应:用于管理后台或简单的 Web 页面。
  6. 重定向响应:用于认证流程或 URL 迁移。
  7. 流式响应:用于实时数据传输或大文件处理。

JSON 响应(80%+ 场景)

JSON 是 Web API 中最常见的响应格式,FastAPI 天然支持通过返回 Python 字典或 Pydantic 模型自动序列化为 JSON 响应

python 复制代码
# 响应json
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Union,TypeVar,Generic
import uvicorn
app = FastAPI()

# 字典方式
@app.get("/items/dict")
async def get_item_dict(name, age):
    return {"name": name, "age": age}

# 定义模型
class Item(BaseModel):
    id:int
    name:str
    tags:list[str]=[]
@app.get("/items/model")
async def get_item_model():
    return Item(id=2,name='初见',tags=['1111'])

# response_model响应数据校验
# response_model_exclude_unset 如果设置值就返回,没有则不返回
@app.get("/items/model1",response_model=Item,response_model_exclude_unset=True)
async def get_item_model1():
    return Item(id=2,name='初见',tags=['1111'])

# 组合模型
# Generic定义泛型模型
T=TypeVar('T')
class SuccessResponse(BaseModel,Generic[T]):
    status:str='success'
    data:T
class ErrorResponse(BaseModel):
    status:str='error'
    message:str
    code:int
@app.get("/items/{id}",response_model=Union[SuccessResponse[Item],ErrorResponse],response_model_exclude_unset=True)
async def get_item_id(id:int):
    if id == 1:
        # 定义要返回的数据
        item=Item(id=1,name='初见',tags=['vue','python'])
        return SuccessResponse[Item](data=item)
    else:
        return ErrorResponse(message='id is not 1',code=400)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run('main_res_json:app', host="127.0.0.1", port=8001, reload=True)

企业级技巧:

  • 通过 response_model 实现响应数据校验和 OpenAPI 文档自动生成
  • 使用 response_model_exclude_unset=True 过滤未设置的默认值字段
  • 组合模型:response_model=Union[SuccessResponse[Item], ErrorResponse]

十五、FastAPI响应数据-列表格式

列表响应是指 API 返回一组数据的响应,通常以 JSON 格式返回一个数组或包含数组的对象。常见场景包括:

  • 分页查询:返回数据的一部分(如每页 10 条记录),避免一次性加载所有数据。
  • 批量数据返回:返回符合条件的全部或部分数据(如所有订单、日志)。
  • 列表响应通常包含:
    • 数据列表:核心数据(例如商品列表、日志记录)。
    • 分页元数据:如总记录数、当前页码、每页记录数、总页数等。
    • 状态信息:如请求状态(成功或失败)。
    • 过滤/排序信息:描述当前返回的数据是如何过滤或排序的

示例

python 复制代码
from fastapi import FastAPI, Query
from pydantic import BaseModel
from typing import List, Optional
from fastapi.responses import JSONResponse

app = FastAPI()

# 定义商品模型
class Item(BaseModel):
    id: int
    name: str
    price: float
    category: str
# 定义分页元数据模型
class Pagination(BaseModel):
    total: int
    page: int
    page_size: int
    total_pages: int
# 定义列表响应模型
class ListResponse(BaseModel):
    status: str = "success"
    data: List[Item]
    pagination: Pagination
# 模拟数据库数据
DB = [
    Item(id=i, name=f"Apple {i}", price=100.0 * i,category="ipad" if i % 2 == 0 else "iphone")
    for i in range(1, 101)
]
# 分页查询商品列表
@app.get("/items1")
async def get_items1():
    return ['Apple1', 'Apple2', 'Apple3']
@app.get("/items2")
async def get_items2():
    return DB

@app.get("/items3", response_model=ListResponse)
async def get_items3(
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(
        10, ge=1, le=100, description="数量"),
    category: Optional[str] = Query(None, description="分类")
):
    # 过滤数据
    filtered_items = DB
    if category:
        filtered_items = [
            item for item in DB if item.category == category]
    # 计算分页参数
    total = len(filtered_items)
    total_pages = (total + page_size - 1) // page_size
    start = (page - 1) * page_size
    end = start + page_size
    # 确保页面有效
    if start >= total and total > 0:
        return JSONResponse(
            status_code=400,
            content={"status": "error", "message": "错误的页码"}
        )
    # 获取分页数据
    paginated_items = filtered_items[start:end]
    # 返回响应
    return ListResponse(
        data=paginated_items,
        pagination=Pagination(
            total=total,
            page=page,
            page_size=page_size,
            total_pages=total_pages
        )
    )

十六、 FastAPI响应数据-文件格式

文件响应是指 API 在响应客户端请求时,返回一个文件内容的 HTTP 响应,通常包含文件的二进制数据或文本数据。

文件响应的关键特点:

  • 内容类型:通过 Content-Type 头指定文件的 MIME 类型,如 application/pdf(PDF 文件)、text/csv(CSV 文件)、application/vnd.ms-excel(Excel 文件)。
  • 文件内容:响应的 body 包含文件的实际数据,可能是二进制(如 PDF、图片)或文本(如 CSV、JSON 文件)。

示例

python 复制代码
# 文件响应
from fastapi import Response
from fastapi.responses import StreamingResponse
from fastapi.responses import FileResponse
from fastapi import FastAPI

app = FastAPI()


@app.get("/download")
async def download_file():
    return FileResponse(
        path="data/fastapi文档.pdf",
        filename="file.pdf",  # 客户端看到的文件名
        media_type="application/pdf"  # 显式设置 MIME 类型
        # path="data/AI变声器.mp4",
        # filename="file2.mp4",  # 客户端看到的文件名
        # media_type="video/mp4"  # 显式设置 MIME 类型
    )


def generate_chunks(file_path: str, chunk_size: int = 1024 * 1024 * 10):
    with open(file_path, "rb") as f:
        while chunk := f.read(chunk_size):
            yield chunk


@app.get("/stream-video")
async def stream_video():
    return StreamingResponse(
        content=generate_chunks("data/AI变声器.mp4"),
        media_type="video/mp4",
    )


@app.get("/custom-file")
async def custom_file():
    binary_data = b"File content"
    return Response(
        content=binary_data,
        media_type="text/plain",
        headers={"Content-Disposition": "attachment; filename=log.txt"}
    )

if __name__ == '__main__':
    import uvicorn
    uvicorn.run('main17:app', host="127.0.0.1", port=8000, reload=True)

十七、 FastAPI响应数据-其它格式

其它响应的格式

  1. 字符串响应
  2. 重定向
  3. HTML 响应
  4. 静态文件
python 复制代码
# 其响应
from fastapi import FastAPI
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI()

@app.get("/hello")
async def hello():
    return "Hello, World!"  # 默认 Content-Type: text/plain; charset=utf-8

@app.get("/redirect")
async def redirect1():
    return RedirectResponse("/hello")

@app.get("/items")
async def create_item(name: str):  # 查询参数
    return {"name": name}

@app.get("/redirect2")
async def redirect2():
    return RedirectResponse("/items?name=张三")

@app.get("/success", response_class=HTMLResponse)
async def success():
    return "<html><body><h1>操作成功!</h1></body></html>"

# 挂载静态目录到 /static 路径
app.mount("/static", StaticFiles(directory="static"), name="static")

app.mount("/app", StaticFiles(directory="template", html=True),
          name="页面"
          )

✒️总结

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对前端端或者对python感兴趣的朋友,请多多关注💖💖💖,咱们一起探讨和努力!!!

👨‍🔧 个人主页 : 前端初见

相关推荐
越甲八千20 小时前
简单fastapi和压测实例
adb·fastapi
逻极1 天前
FastAPI + SQLAlchemy 现代API项目实战:从零到上手的Python MySQL开发指南
python·mysql·fastapi·异步·sqlalchemy
仅此,1 天前
Java请求进入Python FastAPI 后,请求体为空,参数不合法
java·spring boot·python·组合模式·fastapi
Biehmltym1 天前
【AI】07 AI Agent可控风格LLM 问答(含FastAPI 求/返回/路由、跨域访问CORS、System Prompt)
人工智能·prompt·fastapi
Biehmltym1 天前
【AI】08 AI Agent FastAPI + LLM 进阶:基于 Session 的多轮对话| 规则优先 + Tool 调用Agent实现
人工智能·fastapi
曲幽1 天前
一文理清FastAPI参数:从Query、Path到BaseModel的实战指南
python·fastapi·web·form·request·path·body·query·basemodel
vibag2 天前
FastAPI框架
python·pycharm·fastapi
爱敲代码的TOM3 天前
PythonWeb基础-FastAPI使用
python·fastapi
simon_skywalker4 天前
FastAPI实战笔记(二) 数据处理
fastapi