Browse Source

Add missing

pull/14917/head
Yurii Motov 5 months ago
parent
commit
db879a319b
  1. 755
      docs/zh/docs/_llm-test.md
  2. 3
      docs/zh/docs/about/index.md
  3. 61
      docs/zh/docs/advanced/advanced-python-types.md
  4. 482
      docs/zh/docs/alternatives.md
  5. 65
      docs/zh/docs/deployment/fastapicloud.md
  6. 17
      docs/zh/docs/how-to/authentication-error-status-code.md
  7. 56
      docs/zh/docs/how-to/conditional-openapi.md
  8. 185
      docs/zh/docs/how-to/custom-docs-ui-assets.md
  9. 109
      docs/zh/docs/how-to/custom-request-and-route.md
  10. 80
      docs/zh/docs/how-to/extending-openapi.md
  11. 60
      docs/zh/docs/how-to/graphql.md
  12. 135
      docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
  13. 102
      docs/zh/docs/how-to/separate-openapi-schemas.md
  14. 7
      docs/zh/docs/how-to/testing-database.md
  15. 3
      docs/zh/docs/resources/index.md
  16. 11
      docs/zh/docs/translation-banner.md

755
docs/zh/docs/_llm-test.md

@ -0,0 +1,755 @@
# LLM 测试文件 { #llm-test-file }
本文用于测试用于翻译文档的 <abbr title="Large Language Model - 大型语言模型">LLM</abbr> 是否理解 `scripts/translate.py` 中的 `general_prompt` 以及 `docs/{language code}/llm-prompt.md` 中的语言特定提示。语言特定提示会追加到 `general_prompt` 之后。
这里添加的测试会被所有语言特定提示的设计者看到。
用法如下:
* 准备语言特定提示——`docs/{language code}/llm-prompt.md`。
* 将本文重新翻译为你的目标语言(例如使用 `translate.py``translate-page` 命令)。这会在 `docs/{language code}/docs/_llm-test.md` 下创建翻译。
* 检查翻译是否正确。
* 如有需要,改进你的语言特定提示、通用提示,或英文文档。
* 然后手动修正翻译中剩余的问题,确保这是一个优秀的译文。
* 重新翻译,在已有的优秀译文基础上进行。理想情况是 LLM 不再对译文做任何更改。这意味着通用提示和你的语言特定提示已经尽可能完善(有时它仍会做一些看似随机的改动,原因是<a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM 不是确定性算法</a>)。
测试如下:
## 代码片段 { #code-snippets }
//// tab | 测试
这是一个代码片段:`foo`。这是另一个代码片段:`bar`。还有一个:`baz quux`。
////
//// tab | 信息
代码片段的内容应保持不变。
参见 `scripts/translate.py` 中通用提示的 `### Content of code snippets` 部分。
////
## 引号 { #quotes }
//// tab | 测试
昨天,我的朋友写道:"如果你把 incorrectly 拼对了,你就把它拼错了"。我回答:"没错,但 'incorrectly' 错的不是 '"incorrectly"'"。
/// note | 注意
LLM 很可能会把这段翻错。我们只关心在重新翻译时它是否能保持修正后的译文。
///
////
//// tab | 信息
提示词设计者可以选择是否将中性引号转换为排版引号。也可以保持不变。
例如参见 `docs/de/llm-prompt.md` 中的 `### Quotes` 部分。
////
## 代码片段中的引号 { #quotes-in-code-snippets }
//// tab | 测试
`pip install "foo[bar]"`
代码片段中的字符串字面量示例:`"this"`,`'that'`。
一个较难的字符串字面量示例:`f"I like {'oranges' if orange else "apples"}"`
硬核:`Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
////
//// tab | 信息
... 但是,代码片段内的引号必须保持不变。
////
## 代码块 { #code-blocks }
//// tab | 测试
一个 Bash 代码示例...
```bash
# 向宇宙打印问候
echo "Hello universe"
```
...以及一个控制台代码示例...
```console
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting server
Searching for package file structure
```
...以及另一个控制台代码示例...
```console
// 创建目录 "code"
$ mkdir code
// 切换到该目录
$ cd code
```
...以及一个 Python 代码示例...
```Python
wont_work() # 这不会起作用 😱
works(foo="bar") # 这可行 🎉
```
...就这些。
////
//// tab | 信息
代码块中的代码不应被修改,注释除外。
参见 `scripts/translate.py` 中通用提示的 `### Content of code blocks` 部分。
////
## 选项卡与彩色提示框 { #tabs-and-colored-boxes }
//// tab | 测试
/// info | 信息
Some text
///
/// note | 注意
Some text
///
/// note | 技术细节
Some text
///
/// check | 检查
Some text
///
/// tip | 提示
Some text
///
/// warning | 警告
Some text
///
/// danger | 危险
Some text
///
////
//// tab | 信息
选项卡以及 `Info`/`Note`/`Warning`/等提示块,应在竖线(`|`)后添加其标题的翻译。
参见 `scripts/translate.py` 中通用提示的 `### Special blocks``### Tab blocks` 部分。
////
## Web 与内部链接 { #web-and-internal-links }
//// tab | 测试
链接文本应被翻译,链接地址应保持不变:
* [链接到上面的标题](#code-snippets)
* [内部链接](index.md#installation){.internal-link target=_blank}
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">外部链接</a>
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">样式链接</a>
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">脚本链接</a>
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">图片链接</a>
链接文本应被翻译,且链接地址应指向对应的译文页面:
* <a href="https://fastapi.tiangolo.com/zh/" class="external-link" target="_blank">FastAPI 链接</a>
////
//// tab | 信息
链接的文本应被翻译,但地址保持不变。唯一的例外是指向 FastAPI 文档页面的绝对链接,此时应指向对应语言的译文。
参见 `scripts/translate.py` 中通用提示的 `### Links` 部分。
////
## HTML "abbr" 元素 { #html-abbr-elements }
//// tab | 测试
这里有一些包裹在 HTML "abbr" 元素中的内容(有些是虚构的):
### abbr 提供了完整短语 { #the-abbr-gives-a-full-phrase }
* <abbr title="Getting Things Done - 尽管去做">GTD</abbr>
* <abbr title="less than - 小于"><code>lt</code></abbr>
* <abbr title="XML Web Token - XML Web 令牌">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface - 并行服务器网关接口">PSGI</abbr>
### abbr 提供了完整短语与解释 { #the-abbr-gives-a-full-phrase-and-an-explanation }
* <abbr title="Mozilla Developer Network - Mozilla 开发者网络: 为开发者编写的文档,由 Firefox 团队撰写">MDN</abbr>
* <abbr title="Input/Output - 输入/输出: 磁盘读写,网络通信。">I/O</abbr>.
////
//// tab | 信息
"abbr" 元素的 "title" 属性需要按照特定规则进行翻译。
译文可以自行添加 "abbr" 元素以解释英语单词,LLM 不应删除这些元素。
参见 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 部分。
////
## HTML "dfn" 元素 { #html-dfn-elements }
* <dfn title="配置为以某种方式连接并协同工作的机器组">集群</dfn>
* <dfn title="一种使用具有多个隐藏层的人工神经网络的机器学习方法,从输入层到输出层构建了完整的内部结构">深度学习</dfn>
## 标题 { #headings }
//// tab | 测试
### 开发 Web 应用——教程 { #develop-a-webapp-a-tutorial }
Hello.
### 类型提示与注解 { #type-hints-and-annotations }
Hello again.
### 超类与子类 { #super-and-subclasses }
Hello again.
////
//// tab | 信息
关于标题的唯一硬性规则是:LLM 必须保持花括号内的哈希部分不变,以确保链接不会失效。
参见 `scripts/translate.py` 中通用提示的 `### Headings` 部分。
语言特定的说明可参见例如 `docs/de/llm-prompt.md` 中的 `### Headings` 部分。
////
## 文档中使用的术语 { #terms-used-in-the-docs }
//// tab | 测试
* you
* your
* e.g.
* etc.
* `foo` as an `int`
* `bar` as a `str`
* `baz` as a `list`
* the Tutorial - User guide
* the Advanced User Guide
* the SQLModel docs
* the API docs
* the automatic docs
* Data Science
* Deep Learning
* Machine Learning
* Dependency Injection
* HTTP Basic authentication
* HTTP Digest
* ISO format
* the JSON Schema standard
* the JSON schema
* the schema definition
* Password Flow
* Mobile
* deprecated
* designed
* invalid
* on the fly
* standard
* default
* case-sensitive
* case-insensitive
* to serve the application
* to serve the page
* the app
* the application
* the request
* the response
* the error response
* the path operation
* the path operation decorator
* the path operation function
* the body
* the request body
* the response body
* the JSON body
* the form body
* the file body
* the function body
* the parameter
* the body parameter
* the path parameter
* the query parameter
* the cookie parameter
* the header parameter
* the form parameter
* the function parameter
* the event
* the startup event
* the startup of the server
* the shutdown event
* the lifespan event
* the handler
* the event handler
* the exception handler
* to handle
* the model
* the Pydantic model
* the data model
* the database model
* the form model
* the model object
* the class
* the base class
* the parent class
* the subclass
* the child class
* the sibling class
* the class method
* the header
* the headers
* the authorization header
* the `Authorization` header
* the forwarded header
* the dependency injection system
* the dependency
* the dependable
* the dependant
* I/O bound
* CPU bound
* concurrency
* parallelism
* multiprocessing
* the env var
* the environment variable
* the `PATH`
* the `PATH` variable
* the authentication
* the authentication provider
* the authorization
* the authorization form
* the authorization provider
* the user authenticates
* the system authenticates the user
* the CLI
* the command line interface
* the server
* the client
* the cloud provider
* the cloud service
* the development
* the development stages
* the dict
* the dictionary
* the enumeration
* the enum
* the enum member
* the encoder
* the decoder
* to encode
* to decode
* the exception
* to raise
* the expression
* the statement
* the frontend
* the backend
* the GitHub discussion
* the GitHub issue
* the performance
* the performance optimization
* the return type
* the return value
* the security
* the security scheme
* the task
* the background task
* the task function
* the template
* the template engine
* the type annotation
* the type hint
* the server worker
* the Uvicorn worker
* the Gunicorn Worker
* the worker process
* the worker class
* the workload
* the deployment
* to deploy
* the SDK
* the software development kit
* the `APIRouter`
* the `requirements.txt`
* the Bearer Token
* the breaking change
* the bug
* the button
* the callable
* the code
* the commit
* the context manager
* the coroutine
* the database session
* the disk
* the domain
* the engine
* the fake X
* the HTTP GET method
* the item
* the library
* the lifespan
* the lock
* the middleware
* the mobile application
* the module
* the mounting
* the network
* the origin
* the override
* the payload
* the processor
* the property
* the proxy
* the pull request
* the query
* the RAM
* the remote machine
* the status code
* the string
* the tag
* the web framework
* the wildcard
* to return
* to validate
////
//// tab | 信息
这是一份不完整且非规范性的(主要是)技术术语清单,取自文档中常见的词汇。它可能有助于提示词设计者判断哪些术语需要对 LLM 提供额外指引。例如当它总是把一个好的译法改回次优译法,或在你的语言中对某个术语的词形变化有困难时。
参见例如 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 部分。
////
////
翻译(术语)对照:
//// tab | 测试(译文)
* 你
* 你的
* 例如
* 等等
* 将 `foo` 作为 `int`
* 将 `bar` 作为 `str`
* 将 `baz` 作为 `list`
* 教程 - 用户指南
* 高级用户指南
* SQLModel 文档
* API 文档
* 自动文档
* 数据科学
* 深度学习
* 机器学习
* 依赖注入
* HTTP 基本认证
* HTTP 摘要认证
* ISO 格式
* JSON Schema 标准
* JSON 模式
* 模式定义
* 密码流
* 移动端
* 已弃用
* 设计的
* 无效
* 即时
* 标准的
* 默认的
* 区分大小写
* 不区分大小写
* 为应用提供服务
* 为页面提供服务
* 应用
* 应用程序
* 请求
* 响应
* 错误响应
* 路径操作
* 路径操作装饰器
* 路径操作函数
* 主体
* 请求体
* 响应体
* JSON 体
* 表单体
* 文件体
* 函数体
* 参数
* 请求体参数
* 路径参数
* 查询参数
* Cookie 参数
* Header 参数
* 表单参数
* 函数参数
* 事件
* 启动事件
* 服务器的启动
* 关闭事件
* 生命周期事件
* 处理器
* 事件处理器
* 异常处理器
* 处理
* 模型
* Pydantic 模型
* 数据模型
* 数据库模型
* 表单模型
* 模型对象
* 类
* 基类
* 父类
* 子类
* 子类
* 兄弟类
* 类方法
* 请求头
* 请求头
* 授权头
* `Authorization`
* 转发头
* 依赖注入系统
* 依赖
* 可依赖对象
* 依赖项
* I/O 受限
* CPU 受限
* 并发
* 并行
* 多进程
* 环境变量
* 环境变量
* `PATH`
* `PATH` 变量
* 认证
* 认证提供方
* 授权
* 授权表单
* 授权提供方
* 用户进行认证
* 系统对用户进行认证
* CLI
* 命令行界面
* 服务器
* 客户端
* 云服务提供商
* 云服务
* 开发
* 开发阶段
* dict
* 字典
* 枚举
* 枚举
* 枚举成员
* 编码器
* 解码器
* 编码
* 解码
* 异常
* 抛出
* 表达式
* 语句
* 前端
* 后端
* GitHub 讨论
* GitHub Issue
* 性能
* 性能优化
* 返回类型
* 返回值
* 安全
* 安全方案
* 任务
* 后台任务
* 任务函数
* 模板
* 模板引擎
* 类型注解
* 类型提示
* 服务器 worker
* Uvicorn worker
* Gunicorn worker
* worker 进程
* worker 类
* 工作负载
* 部署
* 部署
* SDK
* 软件开发工具包
* `APIRouter`
* `requirements.txt`
* Bearer Token
* 破坏性变更
* Bug
* 按钮
* 可调用对象
* 代码
* 提交
* 上下文管理器
* 协程
* 数据库会话
* 磁盘
* 域名
* 引擎
* 假 X
* HTTP GET 方法
* 项
* 库
* 生命周期
* 锁
* 中间件
* 移动应用
* 模块
* 挂载
* 网络
* 源
* 覆盖
* 负载
* 处理器
* 属性
* 代理
* Pull Request
* 查询
* RAM
* 远程机器
* 状态码
* 字符串
* 标签
* Web 框架
* 通配符
* 返回
* 校验
////
//// tab | 信息(译文)
此清单是不完整且非规范性的,列出(主要是)文档中出现的技术术语。它有助于提示词设计者确定哪些术语需要额外的指引。例如当 LLM 总是把更好的译法改回次优译法,或在你的语言中难以正确变形时。
也可参见 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 部分。
////

3
docs/zh/docs/about/index.md

@ -0,0 +1,3 @@
# 关于 { #about }
关于 FastAPI、其设计、灵感等。🤓

61
docs/zh/docs/advanced/advanced-python-types.md

@ -0,0 +1,61 @@
# 高级 Python 类型 { #advanced-python-types }
这里有一些在使用 Python 类型时可能有用的额外想法。
## 使用 `Union``Optional` { #using-union-or-optional }
如果你的代码因为某些原因不能使用 `|`,例如它不是在类型注解里,而是在 `response_model=` 之类的参数中,那么你可以使用 `typing` 中的 `Union` 来代替竖线(`|`)。
例如,你可以声明某个值可以是 `str``None`
```python
from typing import Union
def say_hi(name: Union[str, None]):
print(f"Hi {name}!")
```
`typing` 也提供了一个声明“可能为 `None`”的快捷方式:`Optional`。
从我非常主观的角度给个小建议:
- 🚨 避免使用 `Optional[SomeType]`
- 改用 ✨`Union[SomeType, None]`✨。
两者是等价的,底层其实也是一样的。但我更推荐使用 `Union` 而不是 `Optional`,因为单词“optional”(可选)看起来会暗示该值是可选的,而它真正的含义是“它可以是 `None`”,即使它并不是可选的,仍然是必填的。
我认为 `Union[SomeType, None]` 更能明确表达其含义。
这只是关于词语和命名的问题,但这些词语会影响你和你的队友如何看待代码。
举个例子,看这段函数:
```python
from typing import Optional
def say_hi(name: Optional[str]):
print(f"Hey {name}!")
```
参数 `name` 被定义为 `Optional[str]`,但它并不是“可选”的,你不能不传这个参数就调用函数:
```Python
say_hi() # 哎呀,这会报错!😱
```
参数 `name` 仍然是必填的(不是“可选”),因为它没有默认值。不过,`name` 接受 `None` 作为取值:
```Python
say_hi(name=None) # 这样可以,None 是有效的 🎉
```
好消息是,在大多数情况下,你可以直接使用 `|` 来定义类型联合:
```python
def say_hi(name: str | None):
print(f"Hey {name}!")
```
因此,通常你不必为像 `Optional``Union` 这样的名字而操心。😎

482
docs/zh/docs/alternatives.md

@ -0,0 +1,482 @@
# 替代方案、灵感与对比 { #alternatives-inspiration-and-comparisons }
是什么启发了 **FastAPI**,它与替代方案的比较,以及它从中学到的东西。
## 介绍 { #intro }
没有前人的工作,就不会有 **FastAPI**
在它诞生之前,已经有许多工具为其提供了灵感。
我曾经多年避免创建一个新框架。起初,我尝试用许多不同的框架、插件和工具来解决 **FastAPI** 所覆盖的全部功能。
但在某个时刻,除了创造一个能提供所有这些功能的东西之外,别无选择;它要吸收以往工具的最佳理念,并以尽可能好的方式组合起来,利用之前都不存在的语言特性(Python 3.6+ 类型提示)。
## 先前的工具 { #previous-tools }
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a> { #django }
它是最流行且被广泛信任的 Python 框架。被用于构建 Instagram 等系统。
它与关系型数据库(如 MySQL、PostgreSQL)耦合相对紧密,因此若要以 NoSQL 数据库(如 Couchbase、MongoDB、Cassandra 等)作为主要存储引擎并不容易。
它最初用于在后端生成 HTML,而不是创建由现代前端(如 React、Vue.js、Angular)或与之通信的其他系统(如 <abbr title="Internet of Things - 物联网">IoT</abbr> 设备)使用的 API。
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a> { #django-rest-framework }
Django REST framework 作为一个灵活工具箱而创建,用于在底层使用 Django 构建 Web API,从而增强其 API 能力。
它被包括 Mozilla、Red Hat、Eventbrite 在内的许多公司使用。
它是最早的“自动 API 文档”的范例之一,这正是启发“寻找” **FastAPI** 的最初想法之一。
/// note | 注意
Django REST Framework 由 Tom Christie 创建。他也是 Starlette 和 Uvicorn 的作者,**FastAPI** 就是基于它们构建的。
///
/// check | 启发 **FastAPI**
提供自动化的 API 文档 Web 界面。
///
### <a href="https://flask.palletsprojects.com" class="external-link" target="_blank">Flask</a> { #flask }
Flask 是一个“微框架”,它不包含数据库集成,也没有像 Django 那样的许多默认内建功能。
这种简单与灵活使得可以将 NoSQL 数据库作为主要的数据存储系统。
由于非常简单,它相对直观易学,尽管文档在某些部分略显偏技术。
它也常用于不一定需要数据库、用户管理,或任何 Django 预构建功能的应用;当然,许多这类功能可以通过插件添加。
这种组件解耦、可按需扩展的“微框架”特性,是我想保留的关键点。
鉴于 Flask 的简洁,它似乎非常适合构建 API。接下来要找的,就是 Flask 版的 “Django REST Framework”。
/// check | 启发 **FastAPI**
- 成为微框架,便于按需组合所需的工具与组件。
- 提供简单易用的路由系统。
///
### <a href="https://requests.readthedocs.io" class="external-link" target="_blank">Requests</a> { #requests }
**FastAPI** 实际上不是 **Requests** 的替代品。它们的作用范围完全不同。
在 FastAPI 应用程序内部使用 Requests 其实非常常见。
尽管如此,FastAPI 依然从 Requests 中获得了不少灵感。
**Requests** 是一个用于与 API 交互(作为客户端)的库,而 **FastAPI** 是一个用于构建 API(作为服务端)的库。
它们处在某种意义上的“对立端”,彼此互补。
Requests 设计非常简单直观,易于使用,且有合理的默认值。同时它也非常强大、可定制。
这就是为什么,正如其官网所说:
> Requests 是有史以来下载量最高的 Python 包之一
它的用法非常简单。例如,进行一次 `GET` 请求,你会这样写:
```Python
response = requests.get("http://example.com/some/url")
```
对应地,FastAPI 的 API 路径操作可能看起来是这样的:
```Python hl_lines="1"
@app.get("/some/url")
def read_url():
return {"message": "Hello World"}
```
可以看到 `requests.get(...)``@app.get(...)` 的相似之处。
/// check | 启发 **FastAPI**
- 提供简单直观的 API。
- 直接、自然地使用 HTTP 方法名(操作)。
- 具备合理默认值,同时支持强大定制能力。
///
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a> { #swagger-openapi }
我想从 Django REST Framework 得到的主要特性之一是自动 API 文档。
随后我发现有一个用于用 JSON(或 YAML,JSON 的扩展)来描述 API 的标准,称为 Swagger。
并且已经有了用于 Swagger API 的 Web 用户界面。因此,只要能为 API 生成 Swagger 文档,就能自动使用这个 Web 界面。
后来,Swagger 交由 Linux 基金会管理,并更名为 OpenAPI。
因此,在谈到 2.0 版本时人们常说 “Swagger”,而 3+ 版本则称为 “OpenAPI”。
/// check | 启发 **FastAPI**
采用并使用开放的 API 规范标准,而非自定义模式。
并集成基于标准的用户界面工具:
- <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>
- <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>
选择这两者是因为它们相当流行且稳定;但稍作搜索,你就能找到数十种 OpenAPI 的替代用户界面(都可以与 **FastAPI** 搭配使用)。
///
### Flask REST 框架 { #flask-rest-frameworks }
有若干基于 Flask 的 REST 框架,但在投入时间精力深入调研后,我发现许多已停止维护或被弃用,并存在多处未解决问题,不太适合采用。
### <a href="https://marshmallow.readthedocs.io/en/stable/" class="external-link" target="_blank">Marshmallow</a> { #marshmallow }
API 系统所需的主要特性之一是数据“<dfn title="也称为:编组、转换">序列化</dfn>”,即将代码(Python)中的数据转换为可通过网络发送的形式。例如,将包含数据库数据的对象转换为 JSON 对象、将 `datetime` 对象转换为字符串等。
API 的另一个重要特性是数据校验,确保数据在给定约束下是有效的。例如,某个字段必须是 `int` 而不是任意字符串。这对传入数据尤其有用。
没有数据校验系统的话,你就得在代码里手写所有检查。
这些正是 Marshmallow 要提供的功能。它是个很棒的库,我之前大量使用过。
但它诞生于 Python 类型提示出现之前。因此,定义每个<dfn title="数据应如何构造的定义">模式</dfn>都需要使用 Marshmallow 提供的特定工具和类。
/// check | 启发 **FastAPI**
使用代码定义“模式”,自动提供数据类型与校验。
///
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a> { #webargs }
API 的另一个重要需求是从传入请求中<dfn title="读取并转换为 Python 数据">解析</dfn>数据。
Webargs 是一个在多个框架(包括 Flask)之上提供该功能的工具。
它在底层使用 Marshmallow 进行数据校验,并且由相同的开发者创建。
在拥有 **FastAPI** 之前,我也大量使用过它,这是个很棒的工具。
/// info | 信息
Webargs 由与 Marshmallow 相同的开发者创建。
///
/// check | 启发 **FastAPI**
对传入请求数据进行自动校验。
///
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a> { #apispec }
Marshmallow 与 Webargs 通过插件提供了校验、解析与序列化。
但文档仍然缺失,于是出现了 APISpec。
它为许多框架提供插件(Starlette 也有插件)。
它的工作方式是:你在处理路由的每个函数的文档字符串里,用 YAML 格式编写模式定义。
然后它会生成 OpenAPI 模式。
这正是它在 Flask、Starlette、Responder 等框架里的工作方式。
但这样我们又回到了在 Python 字符串中维护一套“微语法”(一大段 YAML)的问题上。
编辑器很难为此提供帮助;而且如果我们修改了参数或 Marshmallow 模式,却忘了同步更新那个 YAML 文档字符串,生成的模式就会过时。
/// info | 信息
APISpec 由与 Marshmallow 相同的开发者创建。
///
/// check | 启发 **FastAPI**
支持开放的 API 标准 OpenAPI。
///
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a> { #flask-apispec }
这是一个 Flask 插件,将 Webargs、Marshmallow 与 APISpec 结合在一起。
它利用 Webargs 与 Marshmallow 的信息,通过 APISpec 自动生成 OpenAPI 模式。
这是个很棒却被低估的工具;它理应比许多 Flask 插件更流行。或许是因为它的文档过于简洁与抽象。
这解决了在 Python 文档字符串里书写 YAML(另一套语法)的问题。
在构建 **FastAPI** 之前,Flask + Flask-apispec + Marshmallow + Webargs 的组合是我最喜欢的后端技术栈。
使用它促成了若干 Flask 全栈脚手架的诞生。以下是我(以及若干外部团队)至今使用的主要技术栈:
* <a href="https://github.com/tiangolo/full-stack" class="external-link" target="_blank">https://github.com/tiangolo/full-stack</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
这些全栈脚手架也成为了[**FastAPI** 项目脚手架](project-generation.md){.internal-link target=_blank}的基础。
/// info | 信息
Flask-apispec 由与 Marshmallow 相同的开发者创建。
///
/// check | 启发 **FastAPI**
从定义序列化与校验的同一份代码自动生成 OpenAPI 模式。
///
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a>(以及 <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>) { #nestjs-and-angular }
这甚至不是 Python。NestJS 是一个 JavaScript(TypeScript)的 NodeJS 框架,受 Angular 启发。
它实现了与 Flask-apispec 有些类似的效果。
它集成了受 Angular 2 启发的依赖注入系统。与我所知的其他依赖注入系统一样,需要预先注册“可注入项”,因此会增加冗长与重复。
由于参数用 TypeScript 类型描述(类似 Python 类型提示),编辑器支持相当好。
但由于 TypeScript 的类型在编译为 JavaScript 后不会保留,无法只依赖这些类型同时定义校验、序列化与文档。受此以及一些设计决策影响,为了获得校验、序列化与自动 schema 生成,需要在许多位置添加装饰器,因此代码会相当冗长。
它对嵌套模型的支持并不好。如果请求的 JSON 体是包含嵌套 JSON 对象的 JSON 对象,则无法被正确文档化和校验。
/// check | 启发 **FastAPI**
使用 Python 类型以获得出色的编辑器支持。
拥有强大的依赖注入系统,并设法尽量减少代码重复。
///
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a> { #sanic }
它是最早的一批基于 `asyncio` 的极速 Python 框架之一,且做得与 Flask 很相似。
/// note | 技术细节
它使用了 <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> 来替代 Python 默认的 `asyncio` 循环。这正是它如此之快的原因。
它显然启发了 Uvicorn 和 Starlette;在公开的基准测试中,它们目前比 Sanic 更快。
///
/// check | 启发 **FastAPI**
找到实现疯狂性能的路径。
这就是 **FastAPI** 基于 Starlette 的原因,因为它是目前可用的最快框架(由第三方基准测试验证)。
///
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a> { #falcon }
Falcon 是另一个高性能 Python 框架,它被设计为精简且可作为 Hug 等其他框架的基础。
它设计为接收两个参数的函数:一个“request”和一个“response”。然后从 request 中“读取”,向 response 中“写入”。由于这种设计,无法用标准的 Python 类型提示将请求参数和请求体声明为函数形参。
因此,数据校验、序列化与文档要么需要手写完成,无法自动化;要么需要在 Falcon 之上实现一个框架,例如 Hug。其他受 Falcon 设计启发、采用“一个 request 对象 + 一个 response 对象作为参数”的框架也有同样的区别。
/// check | 启发 **FastAPI**
寻找获得卓越性能的方法。
与 Hug(Hug 基于 Falcon)一起,启发 **FastAPI** 在函数中声明一个 `response` 参数。尽管在 FastAPI 中它是可选的,主要用于设置 headers、cookies 和可选的状态码。
///
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a> { #molten }
我在构建 **FastAPI** 的早期阶段发现了 Molten。它有不少相似的想法:
* 基于 Python 类型提示。
* 从这些类型获得校验与文档。
* 依赖注入系统。
它没有使用像 Pydantic 这样的第三方数据校验、序列化与文档库,而是有自己的实现。因此这些数据类型定义不太容易在其他地方复用。
它需要稍微冗长一些的配置。并且由于基于 WSGI(而非 ASGI),它并未设计为充分利用 Uvicorn、Starlette、Sanic 等工具所提供的高性能。
其依赖注入系统需要预先注册依赖,且依赖根据声明的类型来解析。因此无法为同一类型声明多于一个“组件”。
路由在一个地方集中声明,使用在其他地方声明的函数(而不是使用可以直接放在处理端点函数之上的装饰器)。这更接近 Django 的做法,而不是 Flask(和 Starlette)。它在代码中割裂了相对紧耦合的内容。
/// check | 启发 **FastAPI**
通过模型属性的“默认值”为数据类型定义额外校验。这提升了编辑器支持,而这在当时的 Pydantic 中尚不可用。
这实际上促成了对 Pydantic 的部分更新,以支持这种校验声明风格(这些功能现已在 Pydantic 中可用)。
///
### <a href="https://github.com/hugapi/hug" class="external-link" target="_blank">Hug</a> { #hug }
Hug 是最早使用 Python 类型提示来声明 API 参数类型的框架之一。这一绝妙想法也启发了其他工具。
它在声明中使用自定义类型而不是标准的 Python 类型,但这依然是巨大的进步。
它也是最早生成一个自定义 JSON 模式来声明整个 API 的框架之一。
它并不基于 OpenAPI 与 JSON Schema 这类标准。因此与其他工具(如 Swagger UI)的集成并非一帆风顺。但它仍是非常有创新性的想法。
它有一个有趣且少见的特性:使用同一框架,可以同时创建 API 与 CLI。
由于基于同步 Python Web 框架的上一代标准(WSGI),它无法处理 WebSocket 等,尽管它的性能仍然很高。
/// info | 信息
Hug 由 Timothy Crosley 创建,他也是 <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a> 的作者,这是一个能自动排序 Python 文件中导入的优秀工具。
///
/// check | 启发 **FastAPI** 的想法:
Hug 启发了 APIStar 的部分设计,也是我当时最看好的工具之一,与 APIStar 并列。
Hug 促使 **FastAPI** 使用 Python 类型提示来声明参数,并自动生成定义整个 API 的模式。
Hug 启发 **FastAPI** 在函数中声明 `response` 参数,用于设置 headers 与 cookies。
///
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5) { #apistar-0-5 }
就在决定动手构建 **FastAPI** 之前,我找到了 **APIStar** 服务器。它几乎具备我想要的一切,设计也很出色。
在我见过的框架中,它是最早使用 Python 类型提示来声明参数和请求的实现之一(早于 NestJS 与 Molten)。我与 Hug 几乎同时发现了它。但 APIStar 使用了 OpenAPI 标准。
它基于相同的类型提示,在多处自动进行数据校验、序列化并生成 OpenAPI 模式。
请求体模式定义并未使用与 Pydantic 相同的 Python 类型提示,它更接近 Marshmallow,因此编辑器支持不如 Pydantic 好,但即便如此,APIStar 仍是当时可用的最佳选择。
它在当时拥有最好的性能基准(仅被 Starlette 超越)。
起初它没有自动 API 文档 Web 界面,但我知道我可以把 Swagger UI 加进去。
它有一个依赖注入系统。与上文提到的其他工具一样,需要预先注册组件。但这依然是很棒的特性。
我从未在完整项目中使用过它,因为它没有安全集成,因此我无法用它替代基于 Flask-apispec 的全栈脚手架所具备的全部功能。我曾把“提交一个增加该功能的 PR”放在了待办里。
但随后,项目的重心发生了变化。
它不再是一个 API Web 框架,因为作者需要专注于 Starlette。
现在 APIStar 是一组用于校验 OpenAPI 规范的工具,而不是 Web 框架。
/// info | 信息
APIStar 由 Tom Christie 创建。他还创建了:
* Django REST Framework
* Starlette(**FastAPI** 基于其之上)
* Uvicorn(被 Starlette 与 **FastAPI** 使用)
///
/// check | 启发 **FastAPI**
诞生。
用同一套 Python 类型同时声明多件事(数据校验、序列化与文档),并且还能提供出色的编辑器支持——我认为这是个极其巧妙的想法。
在长时间寻找与测试多种替代之后,APIStar 是当时最好的选择。
随后 APIStar 不再作为服务器存在,而 Starlette 出现,成为实现该体系的更佳基础。这成为构建 **FastAPI** 的最终灵感来源。
我把 **FastAPI** 视为 APIStar 的“精神续作”,并在此基础上,结合前述工具的经验,改进并增强了功能、类型系统及其他各方面。
///
## **FastAPI** 所使用的组件 { #used-by-fastapi }
### <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> { #pydantic }
Pydantic 是一个基于 Python 类型提示来定义数据校验、序列化与文档(使用 JSON Schema)的库。
这使得它极其直观。
它可与 Marshmallow 类比。尽管在基准测试中它比 Marshmallow 更快。并且由于同样基于 Python 类型提示,编辑器支持优秀。
/// check | **FastAPI** 用它来:
处理所有数据校验、数据序列化与自动模型文档(基于 JSON Schema)。
随后 **FastAPI** 会把这些 JSON Schema 数据纳入 OpenAPI(以及完成其他所有工作)。
///
### <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> { #starlette }
Starlette 是一个轻量级的 <dfn title="构建异步 Python Web 应用的新标准">ASGI</dfn> 框架/工具集,非常适合构建高性能的 asyncio 服务。
它非常简单直观。被设计为易于扩展,且具有模块化组件。
它具备:
* 性能极其出色。
* 支持 WebSocket。
* 进程内后台任务。
* 启动与停止事件。
* 基于 HTTPX 的测试客户端。
* CORS、GZip、静态文件、流式响应。
* 会话与 Cookie 支持。
* 100% 测试覆盖率。
* 100% 类型注解的代码库。
* 极少的强依赖。
Starlette 目前是测试中最快的 Python 框架。仅次于 Uvicorn,它不是框架,而是服务器。
Starlette 提供了 Web 微框架的全部基础能力。
但它不提供自动的数据校验、序列化或文档。
这正是 **FastAPI** 在其之上增加的主要内容之一,全部基于 Python 类型提示(通过 Pydantic)。此外还有依赖注入系统、安全工具、OpenAPI 模式生成等。
/// note | 技术细节
ASGI 是由 Django 核心团队成员推动的新“标准”。它尚不是正式的“Python 标准”(PEP),尽管正朝此方向推进。
尽管如此,已有多种工具将其作为“标准”使用。这极大提升了互操作性:你可以把 Uvicorn 换成其他 ASGI 服务器(如 Daphne 或 Hypercorn),或添加 ASGI 兼容的工具,如 `python-socketio`
///
/// check | **FastAPI** 用它来:
处理所有核心 Web 部分,并在其之上扩展功能。
`FastAPI` 类本身直接继承自 `Starlette`
因此,凡是你能用 Starlette 完成的事,也能直接用 **FastAPI** 完成;可以把它看作“加速版”的 Starlette。
///
### <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a> { #uvicorn }
Uvicorn 是一个基于 uvloop 与 httptools 构建的极速 ASGI 服务器。
它不是 Web 框架,而是服务器。例如它不提供按路径路由的工具——这是 Starlette(或 **FastAPI**)这类框架在其之上提供的功能。
它是 Starlette 与 **FastAPI** 推荐的服务器。
/// check | **FastAPI** 推荐将其作为:
运行 **FastAPI** 应用的主要 Web 服务器。
你也可以使用 `--workers` 命令行选项以获得异步的多进程服务器。
更多细节见[部署](deployment/index.md){.internal-link target=_blank}一节。
///
## 基准与速度 { #benchmarks-and-speed }
要理解、比较并查看 Uvicorn、Starlette 与 FastAPI 之间的差异,请查看[基准](benchmarks.md){.internal-link target=_blank}一节。

65
docs/zh/docs/deployment/fastapicloud.md

@ -0,0 +1,65 @@
# FastAPI Cloud { #fastapi-cloud }
你可以用**一条命令**将你的 FastAPI 应用部署到 <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>,如果还没有,去加入候补名单吧。🚀
## 登录 { #login }
请确保你已有 **FastAPI Cloud** 账号(我们已从候补名单向你发出邀请 😉)。
然后登录:
<div class="termy">
```console
$ fastapi login
You are logged in to FastAPI Cloud 🚀
```
</div>
## 部署 { #deploy }
现在用**一条命令**部署你的应用:
<div class="termy">
```console
$ fastapi deploy
Deploying to FastAPI Cloud...
✅ Deployment successful!
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
就这样!现在你可以通过该 URL 访问你的应用。✨
## 关于 FastAPI Cloud { #about-fastapi-cloud }
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** 由 **FastAPI** 背后的作者与团队打造。
它让你以最小的投入完成 API 的**构建**、**部署**与**访问**。
它把使用 FastAPI 构建应用时的**开发者体验**,同样带到将应用**部署**到云上的过程。🎉
它还会替你处理部署应用时大多数需要的事项,例如:
* HTTPS
* 副本、基于请求的自动伸缩
* 等等
FastAPI Cloud 是 *FastAPI and friends* 开源项目的主要赞助方与资金提供者。✨
## 部署到其他云服务商 { #deploy-to-other-cloud-providers }
FastAPI 是开源的,并基于标准。你可以将 FastAPI 应用部署到你选择的任意云服务商。
按照你所选云服务商的指南部署 FastAPI 应用即可。🤓
## 部署到你自己的服务器 { #deploy-your-own-server }
在后面的**部署**指南中,我也会讲解所有细节,帮助你理解幕后发生了什么、需要做什么,以及如何自行部署 FastAPI 应用,包括部署到你自己的服务器。🤓

17
docs/zh/docs/how-to/authentication-error-status-code.md

@ -0,0 +1,17 @@
# 使用旧的 403 认证错误状态码 { #use-old-403-authentication-error-status-codes }
在 FastAPI `0.122.0` 版本之前,当内置的安全工具在认证失败后向客户端返回错误时,会使用 HTTP 状态码 `403 Forbidden`
从 FastAPI `0.122.0` 版本开始,它们改用更合适的 HTTP 状态码 `401 Unauthorized`,并在响应中返回合理的 `WWW-Authenticate` 头,遵循 HTTP 规范,<a href="https://datatracker.ietf.org/doc/html/rfc7235#section-3.1" class="external-link" target="_blank">RFC 7235</a><a href="https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized" class="external-link" target="_blank">RFC 9110</a>
但如果由于某些原因你的客户端依赖旧行为,你可以在你的安全类中重写方法 `make_not_authenticated_error` 来回退到旧行为。
例如,你可以创建一个 `HTTPBearer` 的子类,使其返回 `403 Forbidden` 错误,而不是默认的 `401 Unauthorized` 错误:
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}
/// tip | 提示
注意该函数返回的是异常实例,而不是直接抛出它。抛出操作由其余的内部代码完成。
///

56
docs/zh/docs/how-to/conditional-openapi.md

@ -0,0 +1,56 @@
# 按条件配置 OpenAPI { #conditional-openapi }
如果需要,你可以使用设置和环境变量,按环境有条件地配置 OpenAPI,甚至完全禁用它。
## 关于安全、API 和文档 { #about-security-apis-and-docs }
在生产环境隐藏文档界面并不应该成为保护 API 的方式。
这并不会给你的 API 增加任何额外的安全性,*路径操作* 仍然会在原来的位置可用。
如果你的代码里有安全漏洞,它仍然存在。
隐藏文档只会让理解如何与 API 交互变得更困难,也可能让你在生产环境中调试更困难。这大体上可以被视为一种 <a href="https://en.wikipedia.org/wiki/Security_through_obscurity" class="external-link" target="_blank">通过隐藏实现安全</a> 的做法。
如果你想保护你的 API,有很多更好的措施,例如:
- 确保为请求体和响应定义完善的 Pydantic 模型。
- 使用依赖配置所需的权限和角色。
- 绝不要存储明文密码,只存储密码哈希。
- 实现并使用成熟的密码学工具,比如 pwdlib 和 JWT 令牌等。
- 在需要的地方使用 OAuth2 作用域添加更细粒度的权限控制。
- ...等。
尽管如此,你可能确实有非常特定的用例,需要在某些环境(例如生产环境)禁用 API 文档,或根据环境变量的配置来决定。
## 基于设置和环境变量的条件式 OpenAPI { #conditional-openapi-from-settings-and-env-vars }
你可以很容易地使用相同的 Pydantic 设置来配置生成的 OpenAPI 和文档 UI。
例如:
{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}
这里我们声明了设置项 `openapi_url`,其默认值同样是 `"/openapi.json"`
然后在创建 `FastAPI` 应用时使用它。
接着,你可以通过把环境变量 `OPENAPI_URL` 设为空字符串来禁用 OpenAPI(包括文档 UI),例如:
<div class="termy">
```console
$ OPENAPI_URL= uvicorn main:app
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
然后如果你访问 `/openapi.json`、`/docs` 或 `/redoc`,就会得到一个 `404 Not Found` 错误,例如:
```JSON
{
"detail": "Not Found"
}
```

185
docs/zh/docs/how-to/custom-docs-ui-assets.md

@ -0,0 +1,185 @@
# 自托管自定义文档 UI 静态资源 { #custom-docs-ui-static-assets-self-hosting }
API 文档使用 Swagger UI 和 ReDoc,它们各自需要一些 JavaScript 和 CSS 文件。
默认情况下,这些文件从一个 <abbr title="Content Delivery Network - 内容分发网络: 一种服务,通常由多台服务器组成,用于提供静态文件,如 JavaScript 和 CSS。它常用于从更接近客户端的服务器提供这些文件,从而提升性能。">CDN</abbr> 提供。
不过你可以自定义:可以指定特定的 CDN,或自行提供这些文件。
## 为 JavaScript 和 CSS 自定义 CDN { #custom-cdn-for-javascript-and-css }
假设你想使用不同的 <abbr title="Content Delivery Network - 内容分发网络">CDN</abbr>,例如使用 `https://unpkg.com/`
如果你所在的国家/地区屏蔽了某些 URL,这会很有用。
### 关闭自动文档 { #disable-the-automatic-docs }
第一步是关闭自动文档,因为默认它们会使用默认的 CDN。
要关闭它们,在创建 `FastAPI` 应用时将其 URL 设为 `None`
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}
### 包含自定义文档 { #include-the-custom-docs }
现在你可以为自定义文档创建*路径操作*。
你可以复用 FastAPI 的内部函数来创建文档的 HTML 页面,并传入所需参数:
- `openapi_url`:文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。
- `title`:你的 API 标题。
- `oauth2_redirect_url`:这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。
- `swagger_js_url`:你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。这里是自定义的 CDN URL。
- `swagger_css_url`:你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。这里是自定义的 CDN URL。
ReDoc 也类似...
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}
/// tip | 提示
`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。
如果你把 API 与某个 OAuth2 提供方集成,你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。
Swagger UI 会在幕后为你处理这些,但它需要这个“重定向”辅助路径。
///
### 创建一个路径操作进行测试 { #create-a-path-operation-to-test-it }
现在,为了测试一切是否正常,创建一个*路径操作*:
{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}
### 测试 { #test-it }
现在,你应该可以访问 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>,并刷新页面,页面会从新的 CDN 加载这些资源。
## 为文档自托管 JavaScript 和 CSS { #self-hosting-javascript-and-css-for-docs }
如果你需要在离线、无法访问互联网或仅在局域网内时,应用仍能工作,那么自托管 JavaScript 和 CSS 会很有用。
这里你将看到如何在同一个 FastAPI 应用中自行提供这些文件,并配置文档使用它们。
### 项目文件结构 { #project-file-structure }
假设你的项目文件结构如下:
```
.
├── app
│ ├── __init__.py
│ ├── main.py
```
现在创建一个目录来存放这些静态文件。
你的新文件结构可能如下:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static/
```
### 下载文件 { #download-the-files }
下载文档需要的静态文件,并将它们放到 `static/` 目录中。
你通常可以右键点击每个链接,选择类似“将链接另存为...”的选项。
Swagger UI 使用以下文件:
- <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
- <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
而 ReDoc 使用以下文件:
- <a href="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
之后,你的文件结构可能如下:
```
.
├── app
│   ├── __init__.py
│   ├── main.py
└── static
├── redoc.standalone.js
├── swagger-ui-bundle.js
└── swagger-ui.css
```
### 提供静态文件 { #serve-the-static-files }
- 导入 `StaticFiles`
- 在特定路径上“挂载”一个 `StaticFiles()` 实例。
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}
### 测试静态文件 { #test-the-static-files }
启动你的应用,并访问 <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>
你应该会看到一个非常长的 **ReDoc** 的 JavaScript 文件。
它可能以如下内容开头:
```JavaScript
/*! 有关许可信息请参见 redoc.standalone.js.LICENSE.txt */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
这就确认了你的应用能够提供静态文件,并且你把文档所需的静态文件放在了正确的位置。
现在我们可以配置应用,让文档使用这些静态文件。
### 为静态文件关闭自动文档 { #disable-the-automatic-docs-for-static-files }
和使用自定义 CDN 一样,第一步是关闭自动文档,因为默认情况下它们会使用 CDN。
要关闭它们,在创建 `FastAPI` 应用时将其 URL 设为 `None`
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}
### 为静态文件包含自定义文档 { #include-the-custom-docs-for-static-files }
同样地,现在你可以为自定义文档创建*路径操作*。
你可以再次复用 FastAPI 的内部函数来创建文档的 HTML 页面,并传入所需参数:
- `openapi_url`:文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。
- `title`:你的 API 标题。
- `oauth2_redirect_url`:这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。
- `swagger_js_url`:你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。**这是现在由你的应用自己提供的那个**。
- `swagger_css_url`:你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。**这是现在由你的应用自己提供的那个**。
ReDoc 也类似...
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}
/// tip | 提示
`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。
如果你把 API 与某个 OAuth2 提供方集成,你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。
Swagger UI 会在幕后为你处理这些,但它需要这个“重定向”辅助路径。
///
### 创建一个路径操作测试静态文件 { #create-a-path-operation-to-test-static-files }
现在,为了测试一切是否正常,创建一个*路径操作*:
{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}
### 测试静态文件 UI { #test-static-files-ui }
现在,你可以断开 WiFi,访问 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>,并刷新页面。
即使没有互联网,你也能看到 API 的文档并与之交互。

109
docs/zh/docs/how-to/custom-request-and-route.md

@ -0,0 +1,109 @@
# 自定义 Request 和 APIRoute 类 { #custom-request-and-apiroute-class }
在某些情况下,你可能想要重写 `Request``APIRoute` 类使用的逻辑。
尤其是,当你本来会把这些逻辑放到中间件里时,这是一个不错的替代方案。
例如,如果你想在应用处理之前读取或操作请求体。
/// danger | 危险
这是一个“高级”特性。
如果你刚开始使用 **FastAPI**,可以先跳过本节。
///
## 使用场景 { #use-cases }
一些使用场景包括:
* 将非 JSON 的请求体转换为 JSON(例如 <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>)。
* 解压缩使用 gzip 压缩的请求体。
* 自动记录所有请求体日志。
## 处理自定义请求体编码 { #handling-custom-request-body-encodings }
来看如何用自定义的 `Request` 子类来解压 gzip 请求。
以及一个 `APIRoute` 子类来使用该自定义请求类。
### 创建自定义 `GzipRequest` 类 { #create-a-custom-gziprequest-class }
/// tip | 提示
这是一个演示工作原理的示例。如果你需要 Gzip 支持,可以直接使用提供的 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank}。
///
首先,我们创建一个 `GzipRequest` 类,它会重写 `Request.body()` 方法:当请求头中存在相应标记时对请求体进行解压。
如果请求头中没有 `gzip`,则不会尝试解压。
这样,同一个路由类即可同时处理 gzip 压缩和未压缩的请求。
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
### 创建自定义 `GzipRoute` 类 { #create-a-custom-gziproute-class }
接着,我们创建 `fastapi.routing.APIRoute` 的自定义子类来使用 `GzipRequest`
这次,我们会重写 `APIRoute.get_route_handler()` 方法。
该方法返回一个函数,这个函数负责接收请求并返回响应。
这里我们用它把原始请求包装为 `GzipRequest`
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}
/// note | 技术细节
`Request` 拥有 `request.scope` 属性,它就是一个 Python `dict`,包含与请求相关的元数据。
`Request` 还包含 `request.receive`,它是一个用于“接收”请求体的函数。
`scope` 字典和 `receive` 函数都是 ASGI 规范的一部分。
创建一个新的 `Request` 实例需要这两样:`scope` 和 `receive`
想了解更多关于 `Request` 的信息,请查看 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">Starlette 的 Request 文档</a>
///
`GzipRequest.get_route_handler` 返回的函数唯一不同之处是把 `Request` 转换为 `GzipRequest`
这样,在传给我们的路径操作之前,`GzipRequest` 会(在需要时)负责解压数据。
之后,其余处理逻辑完全相同。
但由于我们修改了 `GzipRequest.body`,在 **FastAPI** 需要读取时,请求体会被自动解压。
## 在异常处理器中访问请求体 { #accessing-the-request-body-in-an-exception-handler }
/// tip | 提示
要解决类似问题,使用 `RequestValidationError` 的自定义处理器中的 `body` 往往更简单([处理错误](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank})。
但本示例同样有效,并展示了如何与内部组件交互。
///
我们也可以用相同的方法在异常处理器中访问请求体。
所需仅是在 `try`/`except` 块中处理请求:
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}
如果发生异常,`Request` 实例仍在作用域内,因此我们可以在处理错误时读取并使用请求体:
{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}
## 在路由器中自定义 `APIRoute` 类 { #custom-apiroute-class-in-a-router }
你也可以设置 `APIRouter``route_class` 参数:
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
在此示例中,`router` 下的路径操作将使用自定义的 `TimedRoute` 类,响应中会多一个 `X-Response-Time` 头,包含生成响应所用的时间:
{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}

80
docs/zh/docs/how-to/extending-openapi.md

@ -0,0 +1,80 @@
# 扩展 OpenAPI { #extending-openapi }
在某些情况下,你可能需要修改生成的 OpenAPI 架构(schema)。
本节将介绍如何实现。
## 常规流程 { #the-normal-process }
常规(默认)流程如下。
`FastAPI` 应用(实例)有一个 `.openapi()` 方法,预期返回 OpenAPI 架构。
在创建应用对象时,会注册一个用于 `/openapi.json`(或你在 `openapi_url` 中设置的路径)的路径操作。
它只会返回一个 JSON 响应,内容是应用 `.openapi()` 方法的结果。
默认情况下,`.openapi()` 方法会检查属性 `.openapi_schema` 是否已有内容,若有则直接返回。
如果没有,则使用 `fastapi.openapi.utils.get_openapi` 工具函数生成。
`get_openapi()` 函数接收以下参数:
- `title`:OpenAPI 标题,显示在文档中。
- `version`:你的 API 版本,例如 `2.5.0`
- `openapi_version`:使用的 OpenAPI 规范版本。默认是最新的 `3.1.0`
- `summary`:API 的简短摘要。
- `description`:API 的描述,可包含 Markdown,并会展示在文档中。
- `routes`:路由列表,即已注册的每个路径操作。来自 `app.routes`
/// info | 信息
参数 `summary` 仅在 OpenAPI 3.1.0 及更高版本中可用,FastAPI 0.99.0 及以上版本支持。
///
## 覆盖默认值 { #overriding-the-defaults }
基于以上信息,你可以用同一个工具函数生成 OpenAPI 架构,并按需覆盖其中的各个部分。
例如,让我们添加 <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc 的 OpenAPI 扩展以包含自定义 Logo</a>
### 常规 **FastAPI** { #normal-fastapi }
首先,像平常一样编写你的 **FastAPI** 应用:
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}
### 生成 OpenAPI 架构 { #generate-the-openapi-schema }
然后,在一个 `custom_openapi()` 函数中使用同一个工具函数生成 OpenAPI 架构:
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}
### 修改 OpenAPI 架构 { #modify-the-openapi-schema }
现在你可以添加 ReDoc 扩展,在 OpenAPI 架构的 `info` “对象”中加入自定义 `x-logo`
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}
### 缓存 OpenAPI 架构 { #cache-the-openapi-schema }
你可以把 `.openapi_schema` 属性当作“缓存”,用来存储已生成的架构。
这样一来,用户每次打开 API 文档时,应用就不必重新生成架构。
它只会生成一次,后续请求都会使用同一份缓存的架构。
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}
### 覆盖方法 { #override-the-method }
现在你可以用你的新函数替换 `.openapi()` 方法。
{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}
### 验证 { #check-it }
当你访问 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> 时,你会看到已使用你的自定义 Logo(本例中为 **FastAPI** 的 Logo):
<img src="/img/tutorial/extending-openapi/image01.png">

60
docs/zh/docs/how-to/graphql.md

@ -0,0 +1,60 @@
# GraphQL { #graphql }
由于 **FastAPI** 基于 **ASGI** 标准,因此很容易集成任何也兼容 ASGI 的 **GraphQL** 库。
你可以在同一个应用中将常规的 FastAPI 路径操作与 GraphQL 结合使用。
/// tip | 提示
**GraphQL** 解决一些非常特定的用例。
与常见的 **Web API** 相比,它有各自的**优点**和**缺点**。
请确保评估在你的用例中,这些**好处**是否足以弥补这些**缺点**。 🤓
///
## GraphQL 库 { #graphql-libraries }
以下是一些支持 **ASGI****GraphQL** 库。你可以将它们与 **FastAPI** 一起使用:
* <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a> 🍓
* 提供 <a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">面向 FastAPI 的文档</a>
* <a href="https://ariadnegraphql.org/" class="external-link" target="_blank">Ariadne</a>
* 提供 <a href="https://ariadnegraphql.org/docs/fastapi-integration" class="external-link" target="_blank">面向 FastAPI 的文档</a>
* <a href="https://tartiflette.io/" class="external-link" target="_blank">Tartiflette</a>
* 提供用于 ASGI 集成的 <a href="https://tartiflette.github.io/tartiflette-asgi/" class="external-link" target="_blank">Tartiflette ASGI</a>
* <a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a>
* 可配合 <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a> 使用
## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }
如果你需要或想要使用 **GraphQL**<a href="https://strawberry.rocks/" class="external-link" target="_blank">**Strawberry**</a> 是**推荐**的库,因为它的设计与 **FastAPI** 最为接近,全部基于**类型注解**。
根据你的用例,你可能会更喜欢其他库,但如果你问我,我大概率会建议你先试试 **Strawberry**
下面是一个将 Strawberry 与 FastAPI 集成的小预览:
{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}
你可以在 <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry 文档</a>中了解更多信息。
还有关于 <a href="https://strawberry.rocks/docs/integrations/fastapi" class="external-link" target="_blank">将 Strawberry 与 FastAPI 结合使用</a>的文档。
## Starlette 中较早的 `GraphQLApp` { #older-graphqlapp-from-starlette }
早期版本的 Starlette 包含一个 `GraphQLApp` 类,用于与 <a href="https://graphene-python.org/" class="external-link" target="_blank">Graphene</a> 集成。
它已在 Starlette 中被弃用,但如果你的代码使用了它,你可以轻松**迁移**到 <a href="https://github.com/ciscorn/starlette-graphene3" class="external-link" target="_blank">starlette-graphene3</a>,它覆盖相同的用例,且接口**几乎完全一致**。
/// tip | 提示
如果你需要 GraphQL,我仍然建议看看 <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry</a>,因为它基于类型注解而不是自定义类和类型。
///
## 了解更多 { #learn-more }
你可以在 <a href="https://graphql.org/" class="external-link" target="_blank">GraphQL 官方文档</a>中了解更多关于 **GraphQL** 的内容。
你也可以通过上面的链接阅读各个库的更多信息。

135
docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md

@ -0,0 +1,135 @@
# 从 Pydantic v1 迁移到 Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }
如果你有一个较旧的 FastAPI 应用,可能在使用 Pydantic v1。
FastAPI 0.100.0 同时支持 Pydantic v1 和 v2,会使用你已安装的任一版本。
FastAPI 0.119.0 引入了在 Pydantic v2 内部以 `pydantic.v1` 形式对 Pydantic v1 的部分支持,以便于迁移到 v2。
FastAPI 0.126.0 移除了对 Pydantic v1 的支持,但在一段时间内仍支持 `pydantic.v1`
/// warning | 警告
从 Python 3.14 开始,Pydantic 团队不再为最新的 Python 版本提供 Pydantic v1 的支持。
这也包括 `pydantic.v1`,在 Python 3.14 及更高版本中不再受支持。
如果你想使用 Python 的最新特性,需要确保使用 Pydantic v2。
///
如果你的旧 FastAPI 应用在用 Pydantic v1,这里将向你展示如何迁移到 Pydantic v2,以及 FastAPI 0.119.0 中可帮助你渐进式迁移的功能。
## 官方指南 { #official-guide }
Pydantic 有一份从 v1 迁移到 v2 的官方 <a href="https://docs.pydantic.dev/latest/migration/" class="external-link" target="_blank">迁移指南</a>
其中包含变更内容、校验如何更准确更严格、可能的注意事项等。
你可以阅读以更好地了解变更。
## 测试 { #tests }
请确保你的应用有[测试](../tutorial/testing.md){.internal-link target=_blank},并在持续集成(CI)中运行它们。
这样你就可以升级并确保一切仍按预期工作。
## `bump-pydantic` { #bump-pydantic }
在很多情况下,如果你使用的是未做自定义的常规 Pydantic 模型,可以将从 Pydantic v1 迁移到 v2 的大部分过程自动化。
你可以使用同一 Pydantic 团队提供的 <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a>
该工具会帮助你自动修改大部分需要变更的代码。
之后运行测试检查是否一切正常。如果正常,你就完成了。😎
## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }
Pydantic v2 以子模块 `pydantic.v1` 的形式包含了 Pydantic v1 的全部内容。但在 Python 3.13 以上的版本中不再受支持。
这意味着你可以安装最新的 Pydantic v2,并从该子模块导入并使用旧的 Pydantic v1 组件,就像安装了旧版 Pydantic v1 一样。
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
### FastAPI 对 v2 中 Pydantic v1 的支持 { #fastapi-support-for-pydantic-v1-in-v2 }
自 FastAPI 0.119.0 起,FastAPI 也对 Pydantic v2 内的 Pydantic v1 提供了部分支持,以便迁移到 v2。
因此,你可以将 Pydantic 升级到最新的 v2,并将导入改为使用 `pydantic.v1` 子模块,在很多情况下就能直接工作。
{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
/// warning | 警告
请注意,由于 Pydantic 团队自 Python 3.14 起不再在较新的 Python 版本中支持 Pydantic v1,使用 `pydantic.v1` 在 Python 3.14 及更高版本中也不受支持。
///
### 同一应用中同时使用 Pydantic v1 与 v2 { #pydantic-v1-and-v2-on-the-same-app }
Pydantic 不支持在一个 Pydantic v2 模型的字段中定义 Pydantic v1 模型,反之亦然。
```mermaid
graph TB
subgraph "❌ Not Supported"
direction TB
subgraph V2["Pydantic v2 Model"]
V1Field["Pydantic v1 Model"]
end
subgraph V1["Pydantic v1 Model"]
V2Field["Pydantic v2 Model"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
```
...但是,你可以在同一个应用中分别使用 Pydantic v1 和 v2 的独立模型。
```mermaid
graph TB
subgraph "✅ Supported"
direction TB
subgraph V2["Pydantic v2 Model"]
V2Field["Pydantic v2 Model"]
end
subgraph V1["Pydantic v1 Model"]
V1Field["Pydantic v1 Model"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
```
在某些情况下,甚至可以在 FastAPI 应用的同一个路径操作中同时使用 Pydantic v1 和 v2 模型:
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
在上面的示例中,输入模型是 Pydantic v1 模型,输出模型(在 `response_model=ItemV2` 中定义)是 Pydantic v2 模型。
### Pydantic v1 参数 { #pydantic-v1-parameters }
如果你需要在 Pydantic v1 模型中使用 FastAPI 特有的参数工具,如 `Body`、`Query`、`Form` 等,在完成向 Pydantic v2 的迁移前,可以从 `fastapi.temp_pydantic_v1_params` 导入它们:
{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
### 分步迁移 { #migrate-in-steps }
/// tip | 提示
优先尝试 `bump-pydantic`,如果测试通过且可行,那么你就用一个命令完成了。✨
///
如果 `bump-pydantic` 不适用于你的场景,你可以在同一应用中同时支持 Pydantic v1 和 v2 模型,逐步迁移到 Pydantic v2。
你可以首先将 Pydantic 升级到最新的 v2,并将所有模型的导入改为使用 `pydantic.v1`
然后按模块或分组,逐步把模型从 Pydantic v1 迁移到 v2。🚶

102
docs/zh/docs/how-to/separate-openapi-schemas.md

@ -0,0 +1,102 @@
# 是否为输入和输出分别生成 OpenAPI JSON Schema { #separate-openapi-schemas-for-input-and-output-or-not }
自从发布了 **Pydantic v2**,生成的 OpenAPI 比之前更精确、更**正确**了。😎
事实上,在某些情况下,对于同一个 Pydantic 模型,OpenAPI 中会根据是否带有**默认值**,为输入和输出分别生成**两个 JSON Schema**。
我们来看看它如何工作,以及在需要时如何修改。
## 用于输入和输出的 Pydantic 模型 { #pydantic-models-for-input-and-output }
假设你有一个带有默认值的 Pydantic 模型,例如:
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
### 输入用的模型 { #model-for-input }
如果你像下面这样把该模型用作输入:
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
...那么 `description` 字段将**不是必填项**,因为它的默认值是 `None`
### 文档中的输入模型 { #input-model-in-docs }
你可以在文档中确认,`description` 字段没有**红色星号**,也就是未被标记为必填:
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image01.png">
</div>
### 输出用的模型 { #model-for-output }
但如果你把同一个模型用作输出,例如:
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
...那么因为 `description` 有默认值,即使你**不返回该字段**,它仍然会有这个**默认值**。
### 输出响应数据的模型 { #model-for-output-response-data }
如果你在文档中交互并查看响应,即使代码没有给某个 `description` 字段赋值,JSON 响应中仍包含默认值(`null`):
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
</div>
这意味着它**总会有值**,只是有时该值可能为 `None`(在 JSON 中是 `null`)。
这也意味着,使用你的 API 的客户端无需检查该值是否存在,他们可以**假设该字段总会存在**,只是有时它会是默认值 `None`
在 OpenAPI 中描述这一点的方式,是把该字段标记为**必填**,因为它总会存在。
因此,一个模型的 JSON Schema 会根据它用于**输入还是输出**而有所不同:
- 用于**输入**时,`description` **不是必填**
- 用于**输出**时,它是**必填**(并且可能为 `None`,在 JSON 中为 `null`
### 文档中的输出模型 { #model-for-output-in-docs }
你也可以在文档中查看输出模型,`name` 和 `description` **都**被**红色星号**标记为**必填**
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image03.png">
</div>
### 文档中的输入/输出模型 { #model-for-input-and-output-in-docs }
如果你查看 OpenAPI 中可用的所有 Schema(JSON Schema),你会看到有两个,一个是 `Item-Input`,一个是 `Item-Output`
对于 `Item-Input`,`description` **不是必填**,没有红色星号。
但对于 `Item-Output`,`description` 是**必填**,带有红色星号。
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image04.png">
</div>
借助 **Pydantic v2** 的这个特性,你的 API 文档会更**精确**,如果你有自动生成的客户端和 SDK,它们也会更精确,带来更好的**开发者体验**和一致性。🎉
## 不要分离 Schema { #do-not-separate-schemas }
当然,在某些情况下,你可能希望**输入和输出使用同一个 schema**。
最常见的情形是:你已经有一些自动生成的客户端代码/SDK,你暂时不想更新所有这些自动生成的客户端代码/SDK(也许未来会,但不是现在)。
这种情况下,你可以在 **FastAPI** 中通过参数 `separate_input_output_schemas=False` 禁用该特性。
/// info | 信息
`separate_input_output_schemas` 的支持是在 FastAPI `0.102.0` 中添加的。🤓
///
{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
### 文档中输入/输出使用同一 Schema 的模型 { #same-schema-for-input-and-output-models-in-docs }
现在该模型的输入和输出将只使用一个 schema,即 `Item`,并且其中的 `description` **不是必填**
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>

7
docs/zh/docs/how-to/testing-database.md

@ -0,0 +1,7 @@
# 测试数据库 { #testing-a-database }
你可以在 <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel 文档</a> 中学习数据库、SQL 和 SQLModel。🤓
这里有一个关于在 FastAPI 中使用 SQLModel 的小教程:<a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">使用 SQLModel 搭配 FastAPI 的教程</a>。✨
该教程包含一个关于 <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/" class="external-link" target="_blank">测试 SQL 数据库</a> 的章节。😎

3
docs/zh/docs/resources/index.md

@ -0,0 +1,3 @@
# 资源 { #resources }
更多资源、外部链接等。✈️

11
docs/zh/docs/translation-banner.md

@ -0,0 +1,11 @@
/// details | 🌐 由 AI 与人类协作翻译
本翻译由人类引导的 AI 生成。🤝
可能存在误解原意或不够自然等问题。🤖
你可以通过[帮助我们更好地引导 AI LLM](https://fastapi.tiangolo.com/zh/contributing/#translations)来改进此翻译。
[英文版本](ENGLISH_VERSION_URL)
///
Loading…
Cancel
Save