FastAPI(二)——请求与响应

路径参数

路径参数是URL路径的一部分,用于标识特定的资源。在FastAPI中,可以通过在路径中使用花括号 {} 来定义路径参数,并在函数参数中指定其类型。

python 复制代码
@app.get("/items/{item_id}")
async def read_item(item_id: int):  #如果不指定,默认是str类型。这里实际上进行了类型转换,如果转换失败会返回400错误
    return {"item_id": item_id}

路由匹配顺序

python 复制代码
app01 = APIRouter()
@app01.get("/user/1")
async def get_users():
    return {"userid": "root_user"}

@app01.get("/user/{user_id}")
async def get_users(user_id):
    print(f"user_id: {user_id}")
    return {"userid": user_id}

#运行后输入user_id为1时,访问的是第一个接口,输出{"userid": "root_user"}
#因为路径是从上到下匹配的,顺序很重要

查询参数

函数中声明不属于路径参数的其他函数参数时,他们会自动解释为"查询字符串"参数

python 复制代码
@app02.get("/jobs/{kd}")
async def get_jobs(kd: str, xl: str, gj: str):
    #基于查询参数的业务逻辑处理
    return {
        "kd": kd,
        "xl": xl,
        "gj": gj
    }
#访问路径示例:/jobs/关键字?xl=本科&gj=3-5年

如果查询参数是可选的

python 复制代码
@app02.get("/jobs/{kd}")
async def get_jobs(kd: str, xl: str = None, gj: str = None):#或者 xl: str | None = None
    #基于查询参数的业务逻辑处理
    return {
        "kd": kd,
        "xl": xl,
        "gj": gj
    }
#访问路径示例:/jobs/关键字?xl=本科

请求体数据

请求体数据通常用于POST、PUT等请求方法中,携带需要创建或更新的数据。在FastAPI中,可以使用Pydantic模型来定义请求体的数据结构。

python 复制代码
from pydantic import BaseModel, Field
from datetime import date
from typing import List, Union
from datetime import datetime

app03= APIRouter()

class User(BaseModel):#BaseModel是Pydantic提供的基类,作用是数据验证和序列化
    name: str = "张三"
    age: int = Field(default=0, gt=0, lt=100)
    bir: Union[date, None] = Field(default=None)
    friends: List[int] = []
    description: None | str = None

@app03.post("/data")
async def post_data(data: User):
    print(data.model_dump())
    return data

说明:

  • 使用Pydantic的BaseModel定义了一个User模型,包含name、age、bir、friends和description字段。
  • age字段使用Field进行了更详细的验证,要求其值在0到100之间
  • 在路径操作函数post_data中,data参数的类型是User,这表示请求体的数据将被解析为User模型的实例。
  • 当客户端发送POST请求到/data路径时,FastAPI会自动将请求体的数据解析为User模型,并进行验证。如果数据有效,函数将返回该User实例,否则会返回400错误,说明请求体数据不符合预期格式。
  • data.model_dump()方法用于将Pydantic模型实例转换为字典格式,方便查看和处理数据。
python 复制代码
class User(BaseModel):
    name: str = "张三"
    age: int = Field(default=0, gt=0, lt=100)
    bir: Union[date, None] = Field(default=None)
    friends: List[int] = []
    description: None | str = None

    @field_validator("bir")
    def check_bir(cls, v):
        if v and v > date.today():
            raise ValueError("生日不能大于今天的日期")
        return v

说明:

  • 使用@field_validator装饰器为bir字段添加了一个自定义验证器。
  • 验证器函数check_bir接受两个参数:cls表示模型类本身,v表示要验证的字段值。
  • 在验证器中,首先检查v是否存在且是否大于今天的日期。如果是,则抛出一个ValueError异常,提示生日不能大于今天的日期。
  • 如果验证通过,返回字段值v。

表单数据

表单数据通常用于HTML表单提交的数据。在FastAPI中,可以使用Form类来定义表单字段。

在OAuth2规范的一种使用方式(密码模式)中,客户端通过表单数据提交用户名和密码以获取访问令牌,而不是通过JSON请求体。

FastAPI可以使用Form组件来接受表单数据

python 复制代码
app04= APIRouter()

@app04.post("/register")
async def register(username: str = Form(...), password: str = Form()):
    print(f"用户名:{username},密码:{password}")
    #实现注册的业务逻辑
    return {
        "username": username
    }

文件上传

文件上传通常用于将文件从客户端发送到服务器。在FastAPI中,可以使用File和UploadFile类来处理文件上传。
使用File类上传文件

python 复制代码
@app05.post("/file")
async def get_file(files: bytes = File()):
    #适合小文件上传
    print(f"file", files)
    return {"file": len(files)}

@app05.post("/files")#多文件上传
async def get_files(files: List[bytes] = File()):
    for f in files:
        print(f"file", len(f))
    return {"files": len(files)}

使用UploadFile类上传文件

python 复制代码
@app05.post("/uploadfile")#适合大文件上传
async def upload_file(file: UploadFile):
    print("file:",file)
    path = os.path.join("dir", file.filename)
    with open(path,"wb") as f:
        for line in file.file:
            f.write(line)
    return {
        "file": file.filename
    }

@app05.post("/uploadfiles")#多文件上传
async def upload_files(files: List[UploadFile]):
    for file in files:
        path = os.path.join("dir", file.filename)
        with open(path,"wb") as f:
            for line in file.file:
                f.write(line)
    return {
        "files": [file.filename for file in files]
    }

使用File类 时,文件内容会被读取为字节 数据,适合小文件上传。而使用UploadFile类 时,文件内容以的形式处理,适合大文件上传,可以避免将整个文件加载到内存中。

Request对象

Request对象表示HTTP请求的所有信息,包括请求头、请求体、查询参数等。在FastAPI中,可以通过在路径操作函数中添加Request参数来访问Request对象。

python 复制代码
@app06.post("/request")
async def Request_info(request: Request):
    print("URL:", request.url)
    print("客户端ip:", request.client.host)
    print("客户端宿主:", request.headers.get("user-agent"))
    print("cookies:", request.cookies)#cookies 是一个字典,用处是存储用户相关信息
    return {
        "url": str(request.url),
        "客户端ip": request.client.host,
        "客户端宿主": request.headers.get("user-agent"),
        "cookies": request.cookies
    }

请求静态文件

静态文件 是指不需要服务器动态生成 的文件,如HTML、CSS、JavaScript、图片等。在FastAPI中,可以使用StaticFiles类来处理静态文件的请求。
动态文件 是指需要服务器动态生成的文件,如通过模板引擎生成的HTML页面。在FastAPI中,可以使用Jinja2Templates类来处理动态文件的请求。

python 复制代码
from fastapi import FastAPI,staticfiles
app = FastAPI()
app.mount("/static", staticfiles.StaticFiles(directory="static"))
  • 通过app.mount()方法将/static路径映射到本地的static目录。
  • 当客户端请求/static路径下的文件时,FastAPI会从static目录中查找对应的文件并返回给客户端。

响应模型相关的参数

FastAPI允许我们自定义响应模型,以控制返回给客户端的数据结构和格式。

  1. 前面写得这么多路径函数返回的都是自定义结构的字典数据,FastAPI提供了response_model参数,可以指定响应模型,从而自动将返回的数据转换为指定的模型格式。
python 复制代码
class UserIn(BaseModel):
    username:str
    password:str
    email:EmailStr
    full_name:Union[str,None]=None


class UserOut(BaseModel):
    username:str
    email:EmailStr
    full_name:Union[str,None]=None

@app07.post("/user",response_model=UserOut)
async def create_user(user: UserIn):
    # 模拟将用户信息存储到数据库
    return user
  • 在上面的代码中,定义了两个Pydantic模型UserIn和UserOut,分别表示输入和输出的数据结构。
  • 在路径操作函数create_user中,使用response_model参数指定响应模型为UserOut。
  1. response_model_exclude_unset:排除未设置的字段
python 复制代码
class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []

items={
    "item1": Item(name="Item One", price=10.0),
    "item2": Item(name="Item Two", description="The second item", price=20.0, tax=2.0, tags=["tag3", "tag4"]),
}

@app07.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • 在上面的代码中,定义了一个Item模型,包含多个字段。
  • 在路径操作函数read_item中,使用response_model_exclude_unset=True参数,表示在响应中排除未设置的字段。
  • 当客户端请求/item1时,响应只包含name和price字段,而description、tax和tags字段将被排除,因为它们未设置。
相关推荐
java1234_小锋3 小时前
TensorFlow2 Python深度学习 - 循环神经网络(SimpleRNN)示例
python·深度学习·tensorflow·tensorflow2
java1234_小锋3 小时前
TensorFlow2 Python深度学习 - 通俗理解池化层,卷积层以及全连接层
python·深度学习·tensorflow·tensorflow2
fsnine3 小时前
Python图形化界面——pyqt5教程
开发语言·python·qt
Mongnewer4 小时前
通过虚拟串口和网络UDP进行数据收发的Delphi7, Lazarus, VB6和VisualFreeBasic实践
网络
扶尔魔ocy4 小时前
python程序打包成win的exe应用(以OCR应用为例)
python·ocr·中文识别
Psycho_MrZhang4 小时前
自定义层和读写文件
pytorch·python·深度学习
我也要当昏君4 小时前
6.5 万维网(答案见原书P294)
网络
嶔某5 小时前
网络:传输层协议UDP和TCP
网络·tcp/ip·udp
似水流年 光阴已逝5 小时前
从Excel姓名匹配案例学Python:由点及面的系统化学习指南
开发语言·python·excel