@ -1,48 +1,50 @@
# 路径参数
# 路径参数
你可以使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量" :
FastAPI 支持使用 Python 字符串格式化语法声明**路径参数**(**变量**) :
```Python hl_lines="6-7"
```Python hl_lines="6-7"
{!../../../docs_src/path_params/tutorial001.py!}
{!../../../docs_src/path_params/tutorial001.py!}
```
```
路径参数 `item_id` 的值将作为参数 `item_id` 传递给你的函数 。
这段代码把 路径参数 `item_id` 的值传递给路径函数的参数 `item_id` 。
所以,如果你 运行示例并访问 < a href = "http://127.0.0.1:8000/items/foo" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/foo< / a > ,将会看到 如下响应:
运行示例并访问 < a href = "http://127.0.0.1:8000/items/foo" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/foo< / a > ,可获得 如下响应:
```JSON
```JSON
{"item_id":"foo"}
{"item_id":"foo"}
```
```
## 有类型的路径参数
## 声明路径参数的类型
你可以使用标准的 Python 类型标注为函数中的路径参数声明 类型。
使用 Python 标准类型注解,声明路径操作函数中路径参数的 类型。
```Python hl_lines="7"
```Python hl_lines="7"
{!../../../docs_src/path_params/tutorial002.py!}
{!../../../docs_src/path_params/tutorial002.py!}
```
```
在这个例子中,`item_id` 被声明为 `int` 类型 。
本例把 `item_id` 的类型声明为 `int` 。
!!! check
!!! check "检查"
这将为你的函数提供编辑器支持,包括错误检查、代码补全等等。
## 数据< abbr title = "也被称为:序列化、解析" > 转换< / abbr >
类型声明将为函数提供错误检查、代码补全等编辑器支持。
如果你运行示例并打开浏览器访问 < a href = "http://127.0.0.1:8000/items/3" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/3< / a > ,将得到如下响应:
## 数据< abbr title = "也称为:序列化、解析" > 转换< / abbr >
运行示例并访问 < a href = "http://127.0.0.1:8000/items/3" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/3< / a > ,返回的响应如下:
```JSON
```JSON
{"item_id":3}
{"item_id":3}
```
```
!!! check
!!! check "检查"
注意函数接收(并返回)的值为 3,是一个 Python `int` 值,而不是字符串 `"3"` 。
注意,函数接收并返回的值是 `3` ( `int` ),不是 `"3"` (`str`)。
所以,**FastAPI** 通过上面的类型声明提供了对请求的 自动< abbr title = "将来自 HTTP 请求中的字符串转换为 Python 数据类型" > "解析"< / abbr > 。
**FastAPI** 通过类型声明 自动< abbr title = "将来自 HTTP 请求中的字符串转换为 Python 数据类型" > **解析**请求中的数据< /abbr > 。
## 数据校验
## 数据校验
但如果你 通过浏览器访问 < a href = "http://127.0.0.1:8000/items/foo" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/foo< / a > ,你会看到一个清晰可读的 HTTP 错误 :
通过浏览器访问 < a href = "http://127.0.0.1:8000/items/foo" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/foo< / a > ,接收如下 HTTP 错误信息 :
```JSON
```JSON
{
{
@ -59,86 +61,91 @@
}
}
```
```
因为路径参数 `item_id` 传入的值为 `"foo"` ,它不是一个 `int` 。
这是因为路径参数 `item_id` 的值 (`"foo"`)的类型不是 `int` 。
值的类型不是 `int ` 而是浮点数(`float`)时也会显示同样的错误,比如: < a href = "http://127.0.0.1:8000/items/4.2" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/4.2。</ a >
!!! check "检查"
如果你提供的是 `float` 而非整数也会出现同样的错误,比如: < a href = "http://127.0.0.1:8000/items/4.2" class = "external-link" target = "_blank" > http://127.0.0.1:8000/items/4.2</ a >
**FastAPI** 使用 Python 类型声明实现了数据校验。
!!! check
注意,上面的错误清晰地指出了未通过校验的具体原因。
所以,通过同样的 Python 类型声明,**FastAPI** 提供了数据校验功能。
注意上面的错误同样清楚地指出了校验未通过的具体原因 。
这在开发调试与 API 交互的代码时非常有用 。
在开发和调试与你的 API 进行交互的代码时,这非常有用。
## 查看文档
## 文档
访问 < a href = "http://127.0.0.1:8000/docs" class = "external-link" target = "_blank" > http://127.0.0.1:8000/docs< / a > ,查看自动生成的 API 文档:
当你打开浏览器访问 < a href = "http://127.0.0.1:8000/docs" class = "external-link" target = "_blank" > http://127.0.0.1:8000/docs< / a > ,你将看到自动生成的交互式 API 文档:
< img src = "/img/tutorial/path-params/image01.png" >
< img src = "https://fastapi.tiangolo.com/img/tutorial/path-params/image01.png" >
!!! check "检查"
!!! check
还是使用 Python 类型声明,**FastAPI** 提供了(集成 Swagger UI 的)API 文档。
再一次,还是通过相同的 Python 类型声明,**FastAPI** 为你提供了自动生成的交互式文档(集成 Swagger UI)。
注意这里的路径参数被声明为一个 整数。
注意,路径参数的类型是 整数。
## 基于标准的好处:可 选文档
## 基于标准的好处,备 选文档
由于生成的 API 模式来自于 < a href = "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class = "external-link" target = "_blank" > OpenAPI< / a > 标准,所以有很多工具与其兼容 。
**FastAPI** 使用 < a href = "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class = "external-link" target = "_blank" > OpenAPI< / a > 生成概图,所以能兼容很多工具 。
正因如此,**FastAPI** 内置了一个可选的 API 文档(使用 Redoc) :
因此,**FastAPI** 还内置了 ReDoc 生成的备选 API 文档,可在此查看 < a href = "http://127.0.0.1:8000/redoc" class = "external-link" target = "_blank" > http://127.0.0.1:8000/redoc< / a > :
< img src = "https://fastapi.tiangolo.com /img/tutorial/path-params/image02.png" >
< img src = "/img/tutorial/path-params/image02.png" >
同样的 ,还有很多其他 兼容的 工具,包括适用于 多种语言的代码生成工具。
同样,还有很多兼容工具,包括多种语言的代码生成工具。
## Pydantic
## Pydantic
所有的数据校验都由 < a href = "https://docs.pydantic.dev/" class = "external-link" target = "_blank" > Pydantic< / a > 在幕后完成,所以你可以从它所有的优点中受益。并且你知道它在这方面非常胜任 。
FastAPI 充分地利用了 < a href = "https://docs.pydantic.dev/" class = "external-link" target = "_blank" > Pydantic< / a > 的优势,用它在后台校验数据。众所周知,Pydantic 擅长的就是数据校验 。
你可以使用同样的类型声明来声明 `str` 、`float`、`bool` 以及许多其他的复合数据类型 。
同样,`str`、`float`、`bool` 以及很多复合数据类型都可以使用类型声明 。
本教程的下一章节将探讨其中的一些 内容。
下一章介绍详细 内容。
## 顺序很重要
## 顺序很重要
在创建*路径操作*时,你会发现有些情况下路径是固定 的。
有时,*路径操作*中的路径是写死 的。
比如 `/users/me` ,我们假设它用来获取关于当前用户的数据.
比如要使用 `/users/me` 获取当前用户的数据。
然后,你还可以使用路径 `/users/{user_id}` 来通过用户 ID 获取关于特定用户的数据。
然后还要使用 `/users/{user_id}` ,通过用户 ID 获取指定用户的数据。
由于*路径操作*是按顺序依次运行的,因此,一定要在 `/users/{user_id}` 之前声明 `/users/me` :
由于*路径操作*是按顺序依次运行的,你需要确保路径 `/users/me` 声明在路径 `/users/{user_id}` 之前:
```Python hl_lines="6 11"
```Python hl_lines="6 11"
{!../../../docs_src/path_params/tutorial003.py!}
{!../../../docs_src/path_params/tutorial003.py!}
```
```
否则,`/users/{user_id}` 的路径还将与 `/users/me` 相匹配,"认为"自己正在接收一个 值为 `"me"` 的 `user_id` 参数。
否则,`/users/{user_id}` 将匹配 `/users/me` ,FastAPI 会**认为**正在接收 值为 `"me"` 的 `user_id` 参数。
## 预设值
## 预设值
如果你有一个接收路径参数的 路径操作,但你希望预先设定可能的有效参数值,则可以 使用标准的 Python < abbr title = "Enumeration" > `Enum`< / abbr > 类型。
路径操作使用 Python 的 < abbr title = "Enumeration" > `Enum`< / abbr > 类型接收预设的*路径参数* 。
### 创建一个 `Enum` 类
### 创建 `Enum` 类
导入 `Enum` 并创建一个 继承自 `str` 和 `Enum` 的子类。
导入 `Enum` 并创建继承自 `str` 和 `Enum` 的子类。
通过从 `str` 继承,API 文档将能够知道这些值必须为 `string` 类型并且能够正确地展示出来 。
通过从 `str` 继承,API 文档就能把值的类型定义为**字符串**,并且能正确渲染 。
然后创建具有固定值的类属性,这些固定值将 是可用的有效值:
然后,创建包含固定值的类属性,这些固定值 是可用的有效值:
```Python hl_lines="1 6-9"
```Python hl_lines="1 6-9"
{!../../../docs_src/path_params/tutorial005.py!}
{!../../../docs_src/path_params/tutorial005.py!}
```
```
!!! info
!!! info "说明"
< a href = "https://docs.python.org/3/library/enum.html" class = "external-link" target = "_blank" > 枚举(或 enums)< / a > 从 3.4 版本起在 Python 中可用。
Python 3.4 及之后版本支持< a href = "https://docs.python.org/3/library/enum.html" class = "external-link" target = "_blank" > 枚举(即 enums)< / a > 。
!!! tip
!!! tip "提示"
如果你想知道,"AlexNet"、"ResNet" 和 "LeNet" 只是机器学习中的< abbr title = "技术上来说是深度学习模型架构" > 模型< / abbr > 名称。
**AlexNet** 、**ResNet**、**LeNet** 是机器学习< abbr title = "技术上来说是深度学习模型架构" > 模型</ abbr > 。
### 声明*路径参数*
### 声明*路径参数*
然后使用你定义的枚举类(`ModelName`)创建一个带有类型标注 的*路径参数*:
使用 Enum 类(`ModelName`)创建使用类型注解 的*路径参数*:
```Python hl_lines="16"
```Python hl_lines="16"
{!../../../docs_src/path_params/tutorial005.py!}
{!../../../docs_src/path_params/tutorial005.py!}
@ -146,17 +153,17 @@
### 查看文档
### 查看文档
因为已经指定了*路径参数*的可用值,所以交互式文档可以恰当地展示它们 :
API 文档会显示预定义*路径参数*的可用值 :
< img src = "https://fastapi.tiangolo.com /img/tutorial/path-params/image03.png" >
< img src = "/img/tutorial/path-params/image03.png" >
### 使用 Python *枚举类型*
### 使用 Python _枚举类型_
*路径参数*的值将是一个*枚举成员* 。
*路径参数*的值是枚举的元素 。
#### 比较*枚举成员 *
#### 比较*枚举元素 *
你可以将它与你创建的 枚举类 `ModelName` 中的*枚举成员*进行比较 :
枚举类 `ModelName` 中的*枚举元素*支持比较操作 :
```Python hl_lines="17"
```Python hl_lines="17"
{!../../../docs_src/path_params/tutorial005.py!}
{!../../../docs_src/path_params/tutorial005.py!}
@ -164,71 +171,82 @@
#### 获取*枚举值*
#### 获取*枚举值*
你可以 使用 `model_name.value` 或通常来说 `your_enum_member.value` 来获取实际的值(在这个例子中为 `str` ):
使用 `model_name.value` 或 `your_enum_member.value` 获取实际的值(本例中为**字符串** ):
```Python hl_lines="19 "
```Python hl_lines="20 "
{!../../../docs_src/path_params/tutorial005.py!}
{!../../../docs_src/path_params/tutorial005.py!}
```
```
!!! tip
!!! tip "提示"
你也可以通过 `ModelName.lenet.value` 来获取值 `"lenet"` 。
使用 `ModelName.lenet.value` 也能获取值 `"lenet"` 。
#### 返回*枚举成员 *
#### 返回*枚举元素 *
你可以从*路径操作*中返回*枚举成员*,即使嵌套在 JSON 结构中(例如一个 `dict` 中) 。
即使嵌套在 JSON 请求体里(例如, `dict` ),也可以从*路径操作*返回*枚举元素* 。
在返回给客户端之前,它们将被转换为对应的值 :
返回给客户端之前,要把枚举元素转换为对应的值(本例中为字符串) :
```Python hl_lines="18-21 "
```Python hl_lines="18 21 23 "
{!../../../docs_src/path_params/tutorial005.py!}
{!../../../docs_src/path_params/tutorial005.py!}
```
```
客户端中的 JSON 响应如下:
```JSON
{
"model_name": "alexnet",
"message": "Deep Learning FTW!"
}
```
## 包含路径的路径参数
## 包含路径的路径参数
假设你有一个*路径操作*,它的路径为 `/files/{file_path}` 。
假设*路径操作*的路径为 `/files/{file_path}` 。
但是你需要 `file_path` 自身也包含*路径*,比如 `home/johndoe/myfile.txt` 。
但需要 `file_path` 中也包含*路径*,比如,`home/johndoe/myfile.txt` 。
因此,该文件的URL将类似于这样:`/files/home/johndoe/myfile.txt`。
此时,该文件的 URL 是这样的 :`/files/home/johndoe/myfile.txt`。
### OpenAPI 支持
### OpenAPI 支持
OpenAPI 不支持任何方式去声明*路径参数*以在其内部包含*路径*,因为这可能会导致难以测试和定义的情况出现 。
OpenAPI 不支持声明包含路径的*路径参数*,因为这会导致测试和定义更加困难 。
不过,你仍然可以通过 Starlette 的一个内部工具在 **FastAPI** 中实现它 。
不过,仍可使用 Starlette 内置工具在 **FastAPI** 中实现这一功能 。
而且文档依旧可以使用,但是不会添加任何该参数应 包含路径的说明。
而且不影响文档正常运行,但是不会添加该参数 包含路径的说明。
### 路径转换器
### 路径转换器
你可以使用直接来自 Starlette 的选项来声明一个 包含*路径*的*路径参数*:
直接使用 Starlette 的选项声明 包含*路径*的*路径参数*:
```
```
/files/{file_path:path}
/files/{file_path:path}
```
```
在这种情况下,参数的名称 为 `file_path` ,结尾部分的 `:path` 说明该参数应匹配任意的 *路径*。
本例中,参数名 为 `file_path` ,结尾部分的 `:path` 说明该参数应匹配*路径*。
因此,你可以这样使用它 :
用法如下 :
```Python hl_lines="6"
```Python hl_lines="6"
{!../../../docs_src/path_params/tutorial004.py!}
{!../../../docs_src/path_params/tutorial004.py!}
```
```
!!! tip
!!! tip "提示"
你可能会需要参数包含 `/home/johndoe/myfile.txt` ,以斜杠(`/`)开头。
注意,包含 `/home/johndoe/myfile.txt` 的路径参数要以斜杠(`/`)开头。
在这种情况下,URL 将会是 `/files//home/johndoe/myfile.txt` ,在`files` 和 `home` 之间有一个双斜杠 (`//`)。
本例中的 URL 是 `/files//home/johndoe/myfile.txt` 。注意,`files` 和 `home` 之间要使用**双斜杠** (`//`)。
## 总 结
## 小 结
使用 **FastAPI** ,通过简短、直观和标准的 Python 类型声明,你将 获得:
通过简短、直观的 Python 标准类型声明,**FastAPI** 可以 获得:
* 编辑器支持:错误检查,代码 补全等
- 编辑器支持:错误检查,代码自动 补全等
* 数据 " < abbr title = "将 来自 HTTP 请求中的字符串转换为 Python 数据类型" > 解析< / abbr > "
- 数据** < abbr title = "把 来自 HTTP 请求中的字符串转换为 Python 数据类型" > 解析< / abbr > **
* 数据校验
- 数据校验
* API 标注和自动生成的 文档
- API 注解和 API 文档
而且你 只需要声明一次即可。
只需要声明一次即可。
这可能是 **FastAPI** 与其他框架相比主要的明显优势(除了原始性能以外) 。
这可能是除了性能以外,**FastAPI** 与其它框架相比的主要优势 。