【Python开发】FastAPI 02:请求参数—路径参数、查询参数

进行接口请求时,请求参数是重中之重了!请求参数指客户端向服务端发送请求时,需要传递给服务端的参数,包括路径参数、查询参数、请求体等。举个例子,如果客户端想要获取某个用户的信息,可以向服务端发送一个 GET 请求,并在请求中传递用户的 ID,这个 ID 就是请求参数。本篇文章介绍路径参数和查询参数。

目录

1 基础_路径参数

1.1 声明路径参数

1.2 声明路径参数声明的类型

1.3 路径操作顺序

1.4 预设值

① 创建一个 Enum 类

② 声明路径参数

③ 使用 Python 枚举类型

1.5 包含路径的路径参数

2 基础_查询参数

2.1 声明查询参数

2.2 默认值

2.3 可选参数

2.4 类型转换

3 数值校验_查询参数

3.1 Query 使用

3.2 通过 Query 校验

① default—默认值

② max_length/min_length—字符最大/小长度

③ regex—正则表达式

④ 声明必需参数

⑤ 声明更多元数据

3.3 查询参数设定为列表/多个值

① List[str]

② list

4 数值校验_路径参数

4.1 Path 使用

4.2 按需对参数排序

4.3 通过 Path 校验

① ge—大于等于

② gt—大于,le—小于等于

③ 总结


📌源码地址:

https://gitee.com/yinyuu/fast-api_study_yinyu

1 基础_路径参数

1.1 声明路径参数

首先简单来声明下路径参数(使用与 Python 格式化字符串相同的语法):

from fastapi import FastAPI

app = FastAPI()

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

代码运行后,路径参数 item_id 的值将作为参数 item_id 传递给你的函数。此时 item_id 不限制类型,输入字符串还是数字均可,不过最终都会被后台转化成字符串。

运行示例并访问 http://127.0.0.1:8000/items/yinyu,将会看到如下响应 👇

若访问 http://127.0.0.1:8000/items/88 响应如下,可看到 88 已转化为字符串 "88"

1.2 声明路径参数声明的类型

然后简单声明下路径参数声明的类型(使用标准的 Python 类型标注):

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

该处的声明类型可以理解为限制类型,也就说该路径参数(查询参数相同)声明类型后,你实际在请求该路径时,只能按照提前声明好的类型进行请求。

此时访问 http://127.0.0.1:8000/items/88,响应正常,88 即为 int 类型。

若此时访问 http://127.0.0.1:8000/items/yinyu,将会返回报错信息,因为 yinyu 是字符串类型,而不是  int 类型,这就是声明了类型的作用 👇

所有的数据校验都由 Pydantic 在幕后完成。

你可以使用同样的类型声明来声明 str、float、bool 以及许多其他的复合数据类型。

📌 文档

此时访问 http://127.0.0.1:8000/docs,将看到自动生成的交互式 API 文档:

1.3 路径操作顺序

在创建路径操作时,会发现有些情况下路径是相同的。

比如:/users/me,假设它用来获取关于当前用户的数据;/users/{user_id} ,假设它用来通过用户 ID 获取关于特定用户的数据。

由于路径操作是按顺序依次运行的,你需要确保路径 /users/me 声明在路径 /users/{user_id} 之前!

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/me")
async def read_user_me():
    return {"user_id": "the current user"}

@app.get("/users/{user_id}")
async def read_user(user_id: str):
    return {"user_id": user_id}

否则,/users/{user_id} 的路径还将与 /users/me 相匹配,"认为"自己正在接收一个值为 "me" 的 user_id 参数。

1.4 预设值

有时只需要给路径参数传递几个常用并且固定的有效值,那么我就可以通过枚举来定制预设值。

① 创建一个 Enum 类

首先导入 Enum 并创建一个继承自 str Enum 的子类,通过从 str 继承,API 文档将能够知道这些值必须为 string 类型并且能够正确地展示出来。

然后创建具有固定值的类属性,比如 yinyu s1s2

from enum import Enum

class ModelName(str, Enum):
    yinyu = "yinyu_v"
    s1 = "s1_v"
    s2 = "s2_v"

枚举(或 enums)从 3.4 版本起在 Python 中可用。

② 声明路径参数

使用定义好的枚举类(ModelName)创建一个带有类型标注的路径参数:

'''包含枚举的路径参数'''
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):

路径参数 model_name 的值将传递给函数 get_model 的参数 model_name,并且这个值的取值范围只能是 ModelName 枚举类中类属性的值。

③ 使用 Python 枚举类型

此时路径参数的值将是一个枚举成员,那么可以做如下的事情,包括比较枚举成员if ModelName is ModelName.yinyu)、获取枚举值(model_name.value)、返回枚举成员(ModelName.s2)等~

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    # 第 1 种判断方式
    if ModelName is ModelName.yinyu:
        return {"model_name": model_name, "message": "yinyu get"}
    # 第 2 种判断方式,效果一样
    if model_name.value == "s1_name":
        return {"model_name": model_name, "message": "s1 get"}
    else:
        return {"model_name": ModelName.s2, "message": "s2 get"}

📌 请求该路径

完全代码:

from enum import Enum
from fastapi import FastAPI

app = FastAPI()

class ModelName(str, Enum):
    yinyu = "yinyu_v"
    s1 = "s1_v"
    s2 = "s2_v"

'''包含枚举的路径参数'''
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    # 第 1 种判断方式
    if ModelName is ModelName.yinyu:
        return {"model_name": model_name, "message": "yinyu get"}
    # 第 2 种判断方式,效果一样
    if model_name.value == "s1_name":
        return {"model_name": model_name, "message": "s1 get"}
    else:
        return {"model_name": ModelName.s2, "message": "s2 get"}

访问 127.0.0.1:8000/models/yinyu_v,响应如下 👇,可以确定地是路径参数中的枚举类校验是以枚举成员的属性为准的,比如 yinyu 的属性值为 yinyu_v

1.5 包含路径的路径参数

适用于文件操作,假设现在你有一个路径操作:/files/{file_path},但是你需要 file_path 本身包含一个 路径, 比如 home/yinyu/myfile.txt

此时使用 Path 转换器就可以进行转换,你可以这样使用它:

@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file_path": file_path}

参数的名称为 file_path,结尾部分的 :path 说明该参数应匹配任意的路径。

你可能会需要参数包含 /home/johndoe/myfile.txt,以斜杠(/)开头。此时,URL 将会是 /files//home/johndoe/myfile.txt,在files 和 home 之间有一个双斜杠(//)。

2 基础_查询参数

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

2.1 声明查询参数

简单声明两个查询参数,可以看到,他和路径参数是不一样的 👇

from fastapi import FastAPI

app = FastAPI()

@app.get("/items1/")
async def read_item(skip: int, limit: int):
    return {"skip": skip,"limit": limit}

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

此时访问 http://127.0.0.1:8000/items/?skip=0&limit=10 👇,同时该查询参数也是必需的,因为这两个查询参数没有设置默认值None

其中:

  • skip:对应的值为 0
  • limit:对应的值为 10

由于它们是 URL 的一部分,因此它们的"原始值"是字符串。 但是为它们声明了 Python 类型(在上面的示例中为 int)时,它们将转换为该类型并针对该类型进行校验。

2.2 默认值

由于查询参数不是路径的固定部分,因此它们可以是可选的,并且可以有默认值。比如给上边接口中的查询参数分别设置默认值为 010

@app.get("/items2/")
async def read_item(skip: int = 0, limit: int = 10):
    return {"skip": skip,"limit": limit}

若此时访问 127.0.0.1:8000/items2/,虽然未设定查询参数,但是查询参数会成为事先设定好的默认值 👇

若此时访问 127.0.0.1:8000/items2/?skip=20skip 将成为在 URL 中设定的值,而 limit 依旧是默认值 👇

2.3 可选参数

通过同样的方式,你可以将它们的默认值设置为 None 来声明可选查询参数:

from typing import Union 

@app.get("/items3/{item_id}")
async def read_item(item_id: str, q: Union[str, None] = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}

其中,查询参数 q 将是可选的,并且默认值为 NoneUnion 的作用是传递两种参数,q 既可以是 str,也可以为空。

若此时访问 127.0.0.1:8000/items3/yinyu,正常返回,说明查询参数 q 已经可选 👇

若此时访问 127.0.0.1:8000/items3/yinyu?q=,也是正常返回,可以简单理解为:q=None,这就是Union 的作用。

 若此时访问 127.0.0.1:8000/items3/yinyu?q=yinyu_v,正常返回 👇

2.4 类型转换

你还可以声明 bool 类型,它们将被自动转换:

@app.get("/items4/{item_id}")
async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False):
    item = {"item_id": item_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item

此时,访问 http://127.0.0.1:8000/items4/yinyu?short=1 ,其中 1 也可以是 True 、true、on、yes中其中一个,包括任何其他的变体形式(大写,首字母大写等等),你的函数接收的 short 参数都会是布尔值 True

对于值为 False 的情况也是一样的。

3 数值校验_查询参数

3.1 Query 使用

Query 是 FastAPI 专门用来装饰查询参数的类,简单使用如下 👇

from typing import Union
#首先从 fastapi 导入 Query
from fastapi import FastAPI,Query

app = FastAPI()

@app.get("/items1/") #然后使用 Query 修饰查询参数
async def read_items(q: Union[str, None] = Query(description="items1 interface")):
    query_items = {"q": q}
    return query_items

description 是 Query 中的一个字段,用来描述该参数;Union 的作用是传递两种参数,q 既可以是 str,也可以为空。

📌 文档

此时访问 http://127.0.0.1:8000/docs,可看到描述信息~

3.2 通过 Query 校验

除了上边的 description ,Query 还可以进行一些额外的校验

① default—默认值

@app.get("/items21/")
async def read_items(q: Union[str, None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

此时,该查询参数等同于 :q: Union[str, None] = None

当然,你也可以将默认值设为有效值:

@app.get("/items22/")
async def read_items(q: str = Query(default="fixedquery")):
    query_items = {"q": q}
    return query_items

此时,该查询参数等同于 :q = "fixedquery"

② max_length/min_length—字符最大/小长度

@app.get("/items2/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50, min_length=3)):
    query_items = {"q": q}
    return query_items

max_length 用于限制查询参数的最大长度,min_length 用于限制查询参数的最小长度,若超出限制将会报错。

注意:max_length 和 min_length 仅可用于 str 类型的查询参数。

③ regex—正则表达式

@app.get("/items4/")
async def read_items(
    q: Union[str, None] = Query(default=None, regex="^fixedquery$")
):
    query_items = {"q": q}
    return query_items

这个指定的正则表达式通过以下规则检查接收到的参数值:

  • ^:以该符号之后的字符开头,符号之前没有字符。
  • fixedquery: 匹配 fixedquery。
  • $: 到此结束,在 fixedquery 之后不匹配任何字符。

也就是说该接口的查询参数只能是"fixedquery",不然就会报错,当然其他的正则表达式都是可以拿来用的!

④ 声明必需参数

首先当使用 Query ,同时需要声明一个值是必需的,只需不声明默认参数:

@app.get("/items5/")
async def read_items(q: str = Query(min_length=3)):
    query_items = {"q": q}
    return query_items

有另一种方法可以显式的声明一个值是必需的,即将该参数的默认值设为 ...

@app.get("/items6/")
async def read_items(q: str = Query(default=..., min_length=3)):
    query_items = {"q": q}
    return query_items

如果不想使用 ...,那么可以从 Pydantic 导入并使用 Required

from pydantic import Required

@app.get("/items7/")
async def read_items(q: str = Query(default=Required, min_length=3)):
    query_items = {"q": q}
    return query_items

总的来说,我认为直接省略 default 即可。

⑤ 声明更多元数据

你可以为查询参数声明额外的校验和元数据,比如:

  • alias:参数别名
  • title:参数标题
  • description:描述
  • deprecated:弃用
@app.get("/items8/")
async def read_items(
    q: Union[str, None] = Query(
        default=None,
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        alias="item-query", #别名
        deprecated=True
    )
):
    query_items = {"q": q}
    return query_items

大家不妨自己去试一下,然后访问 http://127.0.0.1:8000/docs 查看这些元数据在文档中的表现~

3.3 查询参数设定为列表/多个值

我们还可以使用 Query 去接收一组值。

① List[str]

一种方式是使用 List[str] 来接收一组值:

@app.get("/items9/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
    query_items = {"q": q}
    return query_items

此时,访问 localhost:8000/items9/?q=foo&q=bar 👇

这是因为参数 q 中以一个 Python list 的形式接收到查询参数 q 的多个值(foo bar)。

同样的,我们可以定义在没有任何给定值时的默认 list 值:

@app.get("/items10/")
async def read_items(q: List[str] = Query(default=["foo", "bar"])):
    query_items = {"q": q}
    return query_items

② list

你也可以直接使用 list 代替 List [str]

@app.get("/items11/")
async def read_items(q: list = Query(default=[])):
    query_items = {"q": q}
    return query_items

注意:在这种情况下 FastAPI 将不会检查列表的内容。

例如,List[int] 将检查(并记录到文档)列表的内容必须是整数,但是单独的 list 不会。

4 数值校验_路径参数

和前边使用 Query 声明查询参数的更多验证和元数据的方法相同,我们也可以通过Path声明路径参数的相同类型的验证和元数据。

4.1 Path 使用

简单来说,引入 Path,然后

#1.从 fastapi 导入 Path
from fastapi import FastAPI,Path

app = FastAPI()

@app.get("/items1/{item_id}")
async def read_items(
    #2.声明路径参数 item_id的 title 元数据值
    item_id: int = Path(title="The ID of the item to get"),
):
    return {"item_id": item_id}

路径参数总是必需的,你可以在声明时使用 ... 将其标记为必需参数。 不过,即使你不设置或使用 None 声明路径参数,那么也不会有任何影响,它依然会是必需参数。

4.2 按需对参数排序

如果你要声明 q 查询参数而不使用 Query 或任何默认值,并且使用 Path 声明路径参数 item_id 和使用不同的顺序,则 Python 对此有一些特殊的语法。语法规则如下:

  • 传递 * 作为函数的第一个参数。

Python 不会对该 * 做任何事情,但是它将知道之后的所有参数都应作为关键字参数(键值对),也被称为 kwargs,来调用。即使它们没有默认值。

@app.get("/items2/{item_id}")
async def read_items(
        *, 
        item_id: int = Path(title="The ID of the item to get"), 
        q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

此时访问 localhost:8000/items2/2222?q=yinyu 👇

若将 q 和 item_id 顺序调换一下,实际接口请求时也不会收到影响:

@app.get("/items2/{item_id}")
async def read_items(
        *,
        q: str,
        item_id: int = Path(title="The ID of the item to get"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

4.3 通过 Path 校验

使用 Query Path(以及后边其他的类)不仅可以声明字符串约束,还可以声明数值约束(intfloat 等数值类型)。

① ge—大于等于

比如,添加 ge=1 后,item_id 将必须是一个大于(greater than)或等于(equal1 的整数。

@app.get("/items3/{item_id}")
async def read_items(
    *, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

② gt—大于,le—小于等于

同样的规则适用于:

  • gt:大于(greater than)
  • le:小于等于(less than or equal)
@app.get("/items4/{item_id}")
async def read_items(
    *,item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),q: str,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

③ 总结

  • gt:大于(greater than)
  • ge:大于等于(greater than or equal)
  • lt:小于(less than)
  • le:小于等于(less than or equal)

Query、Path 以及你后面会看到的其他类继承自一个共同的 Param 类(不需要直接使用它)。 而且它们都共享相同的所有你已看到并用于添加额外校验和元数据的参数。

<think>好的,我现在要回答用户关于如何在FastAPI中获取请求参数的问题。首先,我需要回忆一下FastAPI的基本用法,特别是处理请求参数的几种方式。记得FastAPI支持路径参数查询参数请求参数等,还有可能涉及表单数据和文件上传。 首先,路径参数。用户可能在URL路径中定义参数,例如/user/{id},这时候在FastAPI中可以通过在路径操作函数的参数中声明来获取。比如定义一个函数def get_user(id: int),这样id就会自动从URL路径中提取并转换为整数类型。需要确认是否正确处理了类型转换和验证,比如如果用户传入非整数字符串,FastAPI会自动返回错误响应。 然后是查询参数,也就是URL中的问号后面的参数,比如/item?skip=0&limit=10。在FastAPI中,这些参数会被视为函数参数的默认值,例如def read_item(skip: int = 0, limit: int = 10)。如果用户没有提供这些参数,就会使用默认值。这里需要注意可选参数和必填参数的处理,以及参数类型的校验。 接下来是请求参数,通常用于POST、PUT等请求,发送JSON数据。在FastAPI中需要用到Pydantic模型来定义数据结构。比如定义一个类Item(BaseModel),然后在路径操作函数中声明参数item: Item,这样FastAPI会自动解析请求体中的JSON数据到Item实例。需要说明如何创建Pydantic模型,并处理嵌套结构或复杂类型。 还有表单数据和文件上传的情况。这时候需要使用Form和File来声明参数,同时需要安装python-multipart库。比如处理表单字段username和password,可以使用def login(username: str = Form(...), password: str = Form(...))。文件上传则用File,比如file: UploadFile = File(...)。需要提醒用户安装必要的依赖,并注意处理文件内容。 此外,可能还需要提到请求参数和cookie参数的获取方式,虽然用户的问题可能主要关注常见的几种参数类型。但为了全面性,可以简要说明如何使用Header和Cookie来获取这些参数。 还需要考虑错误处理,例如参数缺失或类型错误时,FastAPI会自动生成相应的错误响应。比如路径参数类型不匹配会返回422状态码,并给出具体的错误信息。这对于开发调试很有帮助。 最后,可能需要给出一个完整的示例,综合几种参数类型,展示如何在一个路径操作函数中同时使用路径参数查询参数请求参数。例如,一个更新用户信息的接口,接收用户ID作为路径参数,分页参数作为查询参数,用户数据作为请求体。这样用户可以看到不同参数类型的使用方式。 另外,参考用户提供的引用内容中,提到了SQLAlchemy的配置和Django处理外部API请求的例子。虽然FastAPI和Django有所不同,但可以借鉴如何将请求参数与数据库操作结合,比如使用获取的参数查询数据库,或者将参数传递给外部API。不过用户的问题主要是关于获取参数,这部分可能暂时不需要深入数据库操作,但可以提到参数如何用于后续处理,比如存储到数据库或调用其他服务。 总结一下,回答的结构应该是先介绍不同类型的参数,然后分别详细说明每种参数的获取方法,包括代码示例,最后可能综合示例和注意事项。需要确保代码示例符合FastAPI的最新实践,语法正确,并且使用中文解释清楚每个步骤。同时,需要检查是否有遗漏的参数类型,或者是否有常见的错误需要提醒用户注意,比如忘记安装python-multipart导致表单处理失败。</think>### 如何在FastAPI中获取请求参数? 在FastAPI中,获取请求参数主要通过以下几种方式实现,具体方法如下: --- #### 1. **路径参数(Path Parameters)** 路径参数直接嵌入在URL路径中,用于标识资源。例如,获取用户ID为`123`的信息: ```python from fastapi import FastAPI app = FastAPI() @app.get("/users/{user_id}") async def get_user(user_id: int): return {"user_id": user_id} ``` - **说明**:`user_id`会从URL路径中提取并自动转换为整数类型。如果传入非整数(如`abc`),FastAPI会返回类型错误[^1]。 --- #### 2. **查询参数(Query Parameters)** 查询参数是URL中`?`后的键值对,例如`/items?skip=0&limit=10`: ```python @app.get("/items/") async def read_items(skip: int = 0, limit: int = 10): return {"skip": skip, "limit": limit} ``` - **说明**:`skip`和`limit`是可选参数,未提供时使用默认值。若需必填参数,可移除默认值。 --- #### 3. **请求参数(Body Parameters)** 用于接收JSON格式的请求体数据,需结合Pydantic模型: ```python from pydantic import BaseModel class Item(BaseModel): name: str price: float @app.post("/items/") async def create_item(item: Item): return item ``` - **说明**:FastAPI会自动将请求体JSON解析为`Item`对象,支持嵌套模型和复杂类型验证[^1]。 --- #### 4. **表单数据(Form Data)** 处理HTML表单提交的数据(如`application/x-www-form-urlencoded`): ```python from fastapi import Form @app.post("/login/") async def login(username: str = Form(...), password: str = Form(...)): return {"username": username} ``` - **注意**:需安装`python-multipart`库,否则会报错。 --- #### 5. **文件上传(File Uploads)** 接收上传的文件: ```python from fastapi import UploadFile, File @app.post("/upload/") async def upload_file(file: UploadFile = File(...)): return {"filename": file.filename} ``` - **说明**:`UploadFile`提供异步文件流操作,适用于大文件上传。 --- #### 6. **请求参数(Header Parameters)** 从HTTP头部提取参数: ```python from fastapi import Header @app.get("/headers/") async def read_header(user_agent: str | None = Header(default=None)): return {"User-Agent": user_agent} ``` --- #### 7. **Cookie参数(Cookie Parameters)** 获取Cookie中的值: ```python from fastapi import Cookie @app.get("/cookies/") async def read_cookie(session_id: str | None = Cookie(default=None)): return {"session_id": session_id} ``` --- ### 完整示例:综合使用多种参数 ```python @app.put("/users/{user_id}") async def update_user( user_id: int, # 路径参数 item: Item, # 请求参数 q: str | None = None, # 查询参数 token: str = Header(...) # 请求参数 ): return {"user_id": user_id, "item": item, "q": q, "token": token} ``` --- ### 注意事项 - **类型校验**:FastAPI会自动校验参数类型,若类型不匹配会返回`422 Unprocessable Entity`错误。 - **依赖安装**:处理表单或文件时需安装`python-multipart`。 - **异步支持**:所有操作支持异步(`async`),适合高并发场景[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值