From db879a319b15bdd4ab931df9edc8f36020a71859 Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Fri, 13 Feb 2026 14:20:06 +0100 Subject: [PATCH] Add missing --- docs/zh/docs/_llm-test.md | 755 ++++++++++++++++++ docs/zh/docs/about/index.md | 3 + .../zh/docs/advanced/advanced-python-types.md | 61 ++ docs/zh/docs/alternatives.md | 482 +++++++++++ docs/zh/docs/deployment/fastapicloud.md | 65 ++ .../authentication-error-status-code.md | 17 + docs/zh/docs/how-to/conditional-openapi.md | 56 ++ docs/zh/docs/how-to/custom-docs-ui-assets.md | 185 +++++ .../docs/how-to/custom-request-and-route.md | 109 +++ docs/zh/docs/how-to/extending-openapi.md | 80 ++ docs/zh/docs/how-to/graphql.md | 60 ++ ...migrate-from-pydantic-v1-to-pydantic-v2.md | 135 ++++ .../docs/how-to/separate-openapi-schemas.md | 102 +++ docs/zh/docs/how-to/testing-database.md | 7 + docs/zh/docs/resources/index.md | 3 + docs/zh/docs/translation-banner.md | 11 + 16 files changed, 2131 insertions(+) create mode 100644 docs/zh/docs/_llm-test.md create mode 100644 docs/zh/docs/about/index.md create mode 100644 docs/zh/docs/advanced/advanced-python-types.md create mode 100644 docs/zh/docs/alternatives.md create mode 100644 docs/zh/docs/deployment/fastapicloud.md create mode 100644 docs/zh/docs/how-to/authentication-error-status-code.md create mode 100644 docs/zh/docs/how-to/conditional-openapi.md create mode 100644 docs/zh/docs/how-to/custom-docs-ui-assets.md create mode 100644 docs/zh/docs/how-to/custom-request-and-route.md create mode 100644 docs/zh/docs/how-to/extending-openapi.md create mode 100644 docs/zh/docs/how-to/graphql.md create mode 100644 docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md create mode 100644 docs/zh/docs/how-to/separate-openapi-schemas.md create mode 100644 docs/zh/docs/how-to/testing-database.md create mode 100644 docs/zh/docs/resources/index.md create mode 100644 docs/zh/docs/translation-banner.md diff --git a/docs/zh/docs/_llm-test.md b/docs/zh/docs/_llm-test.md new file mode 100644 index 000000000..05c512e99 --- /dev/null +++ b/docs/zh/docs/_llm-test.md @@ -0,0 +1,755 @@ +# LLM 测试文件 { #llm-test-file } + +本文用于测试用于翻译文档的 LLM 是否理解 `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 不再对译文做任何更改。这意味着通用提示和你的语言特定提示已经尽可能完善(有时它仍会做一些看似随机的改动,原因是LLM 不是确定性算法)。 + +测试如下: + +## 代码片段 { #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 +$ fastapi run main.py + FastAPI 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} +* 外部链接 +* 样式链接 +* 脚本链接 +* 图片链接 + +链接文本应被翻译,且链接地址应指向对应的译文页面: + +* FastAPI 链接 + +//// + +//// tab | 信息 + +链接的文本应被翻译,但地址保持不变。唯一的例外是指向 FastAPI 文档页面的绝对链接,此时应指向对应语言的译文。 + +参见 `scripts/translate.py` 中通用提示的 `### Links` 部分。 + +//// + +## HTML "abbr" 元素 { #html-abbr-elements } + +//// tab | 测试 + +这里有一些包裹在 HTML "abbr" 元素中的内容(有些是虚构的): + +### abbr 提供了完整短语 { #the-abbr-gives-a-full-phrase } + +* GTD +* lt +* XWT +* PSGI + +### abbr 提供了完整短语与解释 { #the-abbr-gives-a-full-phrase-and-an-explanation } + +* MDN +* I/O. + +//// + +//// tab | 信息 + +"abbr" 元素的 "title" 属性需要按照特定规则进行翻译。 + +译文可以自行添加 "abbr" 元素以解释英语单词,LLM 不应删除这些元素。 + +参见 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 部分。 + +//// + +## HTML "dfn" 元素 { #html-dfn-elements } + +* 集群 +* 深度学习 + +## 标题 { #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` 部分。 + +//// diff --git a/docs/zh/docs/about/index.md b/docs/zh/docs/about/index.md new file mode 100644 index 000000000..9b73533f7 --- /dev/null +++ b/docs/zh/docs/about/index.md @@ -0,0 +1,3 @@ +# 关于 { #about } + +关于 FastAPI、其设计、灵感等。🤓 diff --git a/docs/zh/docs/advanced/advanced-python-types.md b/docs/zh/docs/advanced/advanced-python-types.md new file mode 100644 index 000000000..bbc9302e8 --- /dev/null +++ b/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` 这样的名字而操心。😎 diff --git a/docs/zh/docs/alternatives.md b/docs/zh/docs/alternatives.md new file mode 100644 index 000000000..8a552c91d --- /dev/null +++ b/docs/zh/docs/alternatives.md @@ -0,0 +1,482 @@ +# 替代方案、灵感与对比 { #alternatives-inspiration-and-comparisons } + +是什么启发了 **FastAPI**,它与替代方案的比较,以及它从中学到的东西。 + +## 介绍 { #intro } + +没有前人的工作,就不会有 **FastAPI**。 + +在它诞生之前,已经有许多工具为其提供了灵感。 + +我曾经多年避免创建一个新框架。起初,我尝试用许多不同的框架、插件和工具来解决 **FastAPI** 所覆盖的全部功能。 + +但在某个时刻,除了创造一个能提供所有这些功能的东西之外,别无选择;它要吸收以往工具的最佳理念,并以尽可能好的方式组合起来,利用之前都不存在的语言特性(Python 3.6+ 类型提示)。 + +## 先前的工具 { #previous-tools } + +### Django { #django } + +它是最流行且被广泛信任的 Python 框架。被用于构建 Instagram 等系统。 + +它与关系型数据库(如 MySQL、PostgreSQL)耦合相对紧密,因此若要以 NoSQL 数据库(如 Couchbase、MongoDB、Cassandra 等)作为主要存储引擎并不容易。 + +它最初用于在后端生成 HTML,而不是创建由现代前端(如 React、Vue.js、Angular)或与之通信的其他系统(如 IoT 设备)使用的 API。 + +### Django REST Framework { #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 界面。 + +/// + +### Flask { #flask } + +Flask 是一个“微框架”,它不包含数据库集成,也没有像 Django 那样的许多默认内建功能。 + +这种简单与灵活使得可以将 NoSQL 数据库作为主要的数据存储系统。 + +由于非常简单,它相对直观易学,尽管文档在某些部分略显偏技术。 + +它也常用于不一定需要数据库、用户管理,或任何 Django 预构建功能的应用;当然,许多这类功能可以通过插件添加。 + +这种组件解耦、可按需扩展的“微框架”特性,是我想保留的关键点。 + +鉴于 Flask 的简洁,它似乎非常适合构建 API。接下来要找的,就是 Flask 版的 “Django REST Framework”。 + +/// check | 启发 **FastAPI**: + +- 成为微框架,便于按需组合所需的工具与组件。 +- 提供简单易用的路由系统。 + +/// + +### Requests { #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 方法名(操作)。 +- 具备合理默认值,同时支持强大定制能力。 + +/// + +### Swagger / OpenAPI { #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 规范标准,而非自定义模式。 + +并集成基于标准的用户界面工具: + +- Swagger UI +- ReDoc + +选择这两者是因为它们相当流行且稳定;但稍作搜索,你就能找到数十种 OpenAPI 的替代用户界面(都可以与 **FastAPI** 搭配使用)。 + +/// + +### Flask REST 框架 { #flask-rest-frameworks } + +有若干基于 Flask 的 REST 框架,但在投入时间精力深入调研后,我发现许多已停止维护或被弃用,并存在多处未解决问题,不太适合采用。 + +### Marshmallow { #marshmallow } + +API 系统所需的主要特性之一是数据“序列化”,即将代码(Python)中的数据转换为可通过网络发送的形式。例如,将包含数据库数据的对象转换为 JSON 对象、将 `datetime` 对象转换为字符串等。 + +API 的另一个重要特性是数据校验,确保数据在给定约束下是有效的。例如,某个字段必须是 `int` 而不是任意字符串。这对传入数据尤其有用。 + +没有数据校验系统的话,你就得在代码里手写所有检查。 + +这些正是 Marshmallow 要提供的功能。它是个很棒的库,我之前大量使用过。 + +但它诞生于 Python 类型提示出现之前。因此,定义每个模式都需要使用 Marshmallow 提供的特定工具和类。 + +/// check | 启发 **FastAPI**: + +使用代码定义“模式”,自动提供数据类型与校验。 + +/// + +### Webargs { #webargs } + +API 的另一个重要需求是从传入请求中解析数据。 + +Webargs 是一个在多个框架(包括 Flask)之上提供该功能的工具。 + +它在底层使用 Marshmallow 进行数据校验,并且由相同的开发者创建。 + +在拥有 **FastAPI** 之前,我也大量使用过它,这是个很棒的工具。 + +/// info | 信息 + +Webargs 由与 Marshmallow 相同的开发者创建。 + +/// + +/// check | 启发 **FastAPI**: + +对传入请求数据进行自动校验。 + +/// + +### APISpec { #apispec } + +Marshmallow 与 Webargs 通过插件提供了校验、解析与序列化。 + +但文档仍然缺失,于是出现了 APISpec。 + +它为许多框架提供插件(Starlette 也有插件)。 + +它的工作方式是:你在处理路由的每个函数的文档字符串里,用 YAML 格式编写模式定义。 + +然后它会生成 OpenAPI 模式。 + +这正是它在 Flask、Starlette、Responder 等框架里的工作方式。 + +但这样我们又回到了在 Python 字符串中维护一套“微语法”(一大段 YAML)的问题上。 + +编辑器很难为此提供帮助;而且如果我们修改了参数或 Marshmallow 模式,却忘了同步更新那个 YAML 文档字符串,生成的模式就会过时。 + +/// info | 信息 + +APISpec 由与 Marshmallow 相同的开发者创建。 + +/// + +/// check | 启发 **FastAPI**: + +支持开放的 API 标准 OpenAPI。 + +/// + +### Flask-apispec { #flask-apispec } + +这是一个 Flask 插件,将 Webargs、Marshmallow 与 APISpec 结合在一起。 + +它利用 Webargs 与 Marshmallow 的信息,通过 APISpec 自动生成 OpenAPI 模式。 + +这是个很棒却被低估的工具;它理应比许多 Flask 插件更流行。或许是因为它的文档过于简洁与抽象。 + +这解决了在 Python 文档字符串里书写 YAML(另一套语法)的问题。 + +在构建 **FastAPI** 之前,Flask + Flask-apispec + Marshmallow + Webargs 的组合是我最喜欢的后端技术栈。 + +使用它促成了若干 Flask 全栈脚手架的诞生。以下是我(以及若干外部团队)至今使用的主要技术栈: + +* https://github.com/tiangolo/full-stack +* https://github.com/tiangolo/full-stack-flask-couchbase +* https://github.com/tiangolo/full-stack-flask-couchdb + +这些全栈脚手架也成为了[**FastAPI** 项目脚手架](project-generation.md){.internal-link target=_blank}的基础。 + +/// info | 信息 + +Flask-apispec 由与 Marshmallow 相同的开发者创建。 + +/// + +/// check | 启发 **FastAPI**: + +从定义序列化与校验的同一份代码自动生成 OpenAPI 模式。 + +/// + +### NestJS(以及 Angular) { #nestjs-and-angular } + +这甚至不是 Python。NestJS 是一个 JavaScript(TypeScript)的 NodeJS 框架,受 Angular 启发。 + +它实现了与 Flask-apispec 有些类似的效果。 + +它集成了受 Angular 2 启发的依赖注入系统。与我所知的其他依赖注入系统一样,需要预先注册“可注入项”,因此会增加冗长与重复。 + +由于参数用 TypeScript 类型描述(类似 Python 类型提示),编辑器支持相当好。 + +但由于 TypeScript 的类型在编译为 JavaScript 后不会保留,无法只依赖这些类型同时定义校验、序列化与文档。受此以及一些设计决策影响,为了获得校验、序列化与自动 schema 生成,需要在许多位置添加装饰器,因此代码会相当冗长。 + +它对嵌套模型的支持并不好。如果请求的 JSON 体是包含嵌套 JSON 对象的 JSON 对象,则无法被正确文档化和校验。 + +/// check | 启发 **FastAPI**: + +使用 Python 类型以获得出色的编辑器支持。 + +拥有强大的依赖注入系统,并设法尽量减少代码重复。 + +/// + +### Sanic { #sanic } + +它是最早的一批基于 `asyncio` 的极速 Python 框架之一,且做得与 Flask 很相似。 + +/// note | 技术细节 + +它使用了 `uvloop` 来替代 Python 默认的 `asyncio` 循环。这正是它如此之快的原因。 + +它显然启发了 Uvicorn 和 Starlette;在公开的基准测试中,它们目前比 Sanic 更快。 + +/// + +/// check | 启发 **FastAPI**: + +找到实现疯狂性能的路径。 + +这就是 **FastAPI** 基于 Starlette 的原因,因为它是目前可用的最快框架(由第三方基准测试验证)。 + +/// + +### Falcon { #falcon } + +Falcon 是另一个高性能 Python 框架,它被设计为精简且可作为 Hug 等其他框架的基础。 + +它设计为接收两个参数的函数:一个“request”和一个“response”。然后从 request 中“读取”,向 response 中“写入”。由于这种设计,无法用标准的 Python 类型提示将请求参数和请求体声明为函数形参。 + +因此,数据校验、序列化与文档要么需要手写完成,无法自动化;要么需要在 Falcon 之上实现一个框架,例如 Hug。其他受 Falcon 设计启发、采用“一个 request 对象 + 一个 response 对象作为参数”的框架也有同样的区别。 + +/// check | 启发 **FastAPI**: + +寻找获得卓越性能的方法。 + +与 Hug(Hug 基于 Falcon)一起,启发 **FastAPI** 在函数中声明一个 `response` 参数。尽管在 FastAPI 中它是可选的,主要用于设置 headers、cookies 和可选的状态码。 + +/// + +### Molten { #molten } + +我在构建 **FastAPI** 的早期阶段发现了 Molten。它有不少相似的想法: + +* 基于 Python 类型提示。 +* 从这些类型获得校验与文档。 +* 依赖注入系统。 + +它没有使用像 Pydantic 这样的第三方数据校验、序列化与文档库,而是有自己的实现。因此这些数据类型定义不太容易在其他地方复用。 + +它需要稍微冗长一些的配置。并且由于基于 WSGI(而非 ASGI),它并未设计为充分利用 Uvicorn、Starlette、Sanic 等工具所提供的高性能。 + +其依赖注入系统需要预先注册依赖,且依赖根据声明的类型来解析。因此无法为同一类型声明多于一个“组件”。 + +路由在一个地方集中声明,使用在其他地方声明的函数(而不是使用可以直接放在处理端点函数之上的装饰器)。这更接近 Django 的做法,而不是 Flask(和 Starlette)。它在代码中割裂了相对紧耦合的内容。 + +/// check | 启发 **FastAPI**: + +通过模型属性的“默认值”为数据类型定义额外校验。这提升了编辑器支持,而这在当时的 Pydantic 中尚不可用。 + +这实际上促成了对 Pydantic 的部分更新,以支持这种校验声明风格(这些功能现已在 Pydantic 中可用)。 + +/// + +### Hug { #hug } + +Hug 是最早使用 Python 类型提示来声明 API 参数类型的框架之一。这一绝妙想法也启发了其他工具。 + +它在声明中使用自定义类型而不是标准的 Python 类型,但这依然是巨大的进步。 + +它也是最早生成一个自定义 JSON 模式来声明整个 API 的框架之一。 + +它并不基于 OpenAPI 与 JSON Schema 这类标准。因此与其他工具(如 Swagger UI)的集成并非一帆风顺。但它仍是非常有创新性的想法。 + +它有一个有趣且少见的特性:使用同一框架,可以同时创建 API 与 CLI。 + +由于基于同步 Python Web 框架的上一代标准(WSGI),它无法处理 WebSocket 等,尽管它的性能仍然很高。 + +/// info | 信息 + +Hug 由 Timothy Crosley 创建,他也是 `isort` 的作者,这是一个能自动排序 Python 文件中导入的优秀工具。 + +/// + +/// check | 启发 **FastAPI** 的想法: + +Hug 启发了 APIStar 的部分设计,也是我当时最看好的工具之一,与 APIStar 并列。 + +Hug 促使 **FastAPI** 使用 Python 类型提示来声明参数,并自动生成定义整个 API 的模式。 + +Hug 启发 **FastAPI** 在函数中声明 `response` 参数,用于设置 headers 与 cookies。 + +/// + +### APIStar (<= 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 } + +### Pydantic { #pydantic } + +Pydantic 是一个基于 Python 类型提示来定义数据校验、序列化与文档(使用 JSON Schema)的库。 + +这使得它极其直观。 + +它可与 Marshmallow 类比。尽管在基准测试中它比 Marshmallow 更快。并且由于同样基于 Python 类型提示,编辑器支持优秀。 + +/// check | **FastAPI** 用它来: + +处理所有数据校验、数据序列化与自动模型文档(基于 JSON Schema)。 + +随后 **FastAPI** 会把这些 JSON Schema 数据纳入 OpenAPI(以及完成其他所有工作)。 + +/// + +### Starlette { #starlette } + +Starlette 是一个轻量级的 ASGI 框架/工具集,非常适合构建高性能的 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。 + +/// + +### Uvicorn { #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}一节。 diff --git a/docs/zh/docs/deployment/fastapicloud.md b/docs/zh/docs/deployment/fastapicloud.md new file mode 100644 index 000000000..0239a1512 --- /dev/null +++ b/docs/zh/docs/deployment/fastapicloud.md @@ -0,0 +1,65 @@ +# FastAPI Cloud { #fastapi-cloud } + +你可以用**一条命令**将你的 FastAPI 应用部署到 FastAPI Cloud,如果还没有,去加入候补名单吧。🚀 + +## 登录 { #login } + +请确保你已有 **FastAPI Cloud** 账号(我们已从候补名单向你发出邀请 😉)。 + +然后登录: + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +## 部署 { #deploy } + +现在用**一条命令**部署你的应用: + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +就这样!现在你可以通过该 URL 访问你的应用。✨ + +## 关于 FastAPI Cloud { #about-fastapi-cloud } + +**FastAPI Cloud** 由 **FastAPI** 背后的作者与团队打造。 + +它让你以最小的投入完成 API 的**构建**、**部署**与**访问**。 + +它把使用 FastAPI 构建应用时的**开发者体验**,同样带到将应用**部署**到云上的过程。🎉 + +它还会替你处理部署应用时大多数需要的事项,例如: + +* HTTPS +* 副本、基于请求的自动伸缩 +* 等等 + +FastAPI Cloud 是 *FastAPI and friends* 开源项目的主要赞助方与资金提供者。✨ + +## 部署到其他云服务商 { #deploy-to-other-cloud-providers } + +FastAPI 是开源的,并基于标准。你可以将 FastAPI 应用部署到你选择的任意云服务商。 + +按照你所选云服务商的指南部署 FastAPI 应用即可。🤓 + +## 部署到你自己的服务器 { #deploy-your-own-server } + +在后面的**部署**指南中,我也会讲解所有细节,帮助你理解幕后发生了什么、需要做什么,以及如何自行部署 FastAPI 应用,包括部署到你自己的服务器。🤓 diff --git a/docs/zh/docs/how-to/authentication-error-status-code.md b/docs/zh/docs/how-to/authentication-error-status-code.md new file mode 100644 index 000000000..466b90e15 --- /dev/null +++ b/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 规范,RFC 7235RFC 9110。 + +但如果由于某些原因你的客户端依赖旧行为,你可以在你的安全类中重写方法 `make_not_authenticated_error` 来回退到旧行为。 + +例如,你可以创建一个 `HTTPBearer` 的子类,使其返回 `403 Forbidden` 错误,而不是默认的 `401 Unauthorized` 错误: + +{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *} + +/// tip | 提示 + +注意该函数返回的是异常实例,而不是直接抛出它。抛出操作由其余的内部代码完成。 + +/// diff --git a/docs/zh/docs/how-to/conditional-openapi.md b/docs/zh/docs/how-to/conditional-openapi.md new file mode 100644 index 000000000..d26b5f3bd --- /dev/null +++ b/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 交互变得更困难,也可能让你在生产环境中调试更困难。这大体上可以被视为一种 通过隐藏实现安全 的做法。 + +如果你想保护你的 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),例如: + +
+ +```console +$ OPENAPI_URL= uvicorn main:app + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +然后如果你访问 `/openapi.json`、`/docs` 或 `/redoc`,就会得到一个 `404 Not Found` 错误,例如: + +```JSON +{ + "detail": "Not Found" +} +``` diff --git a/docs/zh/docs/how-to/custom-docs-ui-assets.md b/docs/zh/docs/how-to/custom-docs-ui-assets.md new file mode 100644 index 000000000..86758aeb6 --- /dev/null +++ b/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 文件。 + +默认情况下,这些文件从一个 CDN 提供。 + +不过你可以自定义:可以指定特定的 CDN,或自行提供这些文件。 + +## 为 JavaScript 和 CSS 自定义 CDN { #custom-cdn-for-javascript-and-css } + +假设你想使用不同的 CDN,例如使用 `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 } + +现在,你应该可以访问 http://127.0.0.1:8000/docs,并刷新页面,页面会从新的 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 使用以下文件: + +- `swagger-ui-bundle.js` +- `swagger-ui.css` + +而 ReDoc 使用以下文件: + +- `redoc.standalone.js` + +之后,你的文件结构可能如下: + +``` +. +├── 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 } + +启动你的应用,并访问 http://127.0.0.1:8000/static/redoc.standalone.js。 + +你应该会看到一个非常长的 **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,访问 http://127.0.0.1:8000/docs,并刷新页面。 + +即使没有互联网,你也能看到 API 的文档并与之交互。 diff --git a/docs/zh/docs/how-to/custom-request-and-route.md b/docs/zh/docs/how-to/custom-request-and-route.md new file mode 100644 index 000000000..8b365987c --- /dev/null +++ b/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(例如 `msgpack`)。 +* 解压缩使用 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` 的信息,请查看 Starlette 的 Request 文档。 + +/// + +由 `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] *} diff --git a/docs/zh/docs/how-to/extending-openapi.md b/docs/zh/docs/how-to/extending-openapi.md new file mode 100644 index 000000000..ad8a1d698 --- /dev/null +++ b/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 架构,并按需覆盖其中的各个部分。 + +例如,让我们添加 ReDoc 的 OpenAPI 扩展以包含自定义 Logo。 + +### 常规 **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 } + +当你访问 http://127.0.0.1:8000/redoc 时,你会看到已使用你的自定义 Logo(本例中为 **FastAPI** 的 Logo): + + diff --git a/docs/zh/docs/how-to/graphql.md b/docs/zh/docs/how-to/graphql.md new file mode 100644 index 000000000..5384f1513 --- /dev/null +++ b/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** 一起使用: + +* Strawberry 🍓 + * 提供 面向 FastAPI 的文档 +* Ariadne + * 提供 面向 FastAPI 的文档 +* Tartiflette + * 提供用于 ASGI 集成的 Tartiflette ASGI +* Graphene + * 可配合 starlette-graphene3 使用 + +## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry } + +如果你需要或想要使用 **GraphQL**,**Strawberry** 是**推荐**的库,因为它的设计与 **FastAPI** 最为接近,全部基于**类型注解**。 + +根据你的用例,你可能会更喜欢其他库,但如果你问我,我大概率会建议你先试试 **Strawberry**。 + +下面是一个将 Strawberry 与 FastAPI 集成的小预览: + +{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *} + +你可以在 Strawberry 文档中了解更多信息。 + +还有关于 将 Strawberry 与 FastAPI 结合使用的文档。 + +## Starlette 中较早的 `GraphQLApp` { #older-graphqlapp-from-starlette } + +早期版本的 Starlette 包含一个 `GraphQLApp` 类,用于与 Graphene 集成。 + +它已在 Starlette 中被弃用,但如果你的代码使用了它,你可以轻松**迁移**到 starlette-graphene3,它覆盖相同的用例,且接口**几乎完全一致**。 + +/// tip | 提示 + +如果你需要 GraphQL,我仍然建议看看 Strawberry,因为它基于类型注解而不是自定义类和类型。 + +/// + +## 了解更多 { #learn-more } + +你可以在 GraphQL 官方文档中了解更多关于 **GraphQL** 的内容。 + +你也可以通过上面的链接阅读各个库的更多信息。 diff --git a/docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md new file mode 100644 index 000000000..2e5445200 --- /dev/null +++ b/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 的官方 迁移指南。 + +其中包含变更内容、校验如何更准确更严格、可能的注意事项等。 + +你可以阅读以更好地了解变更。 + +## 测试 { #tests } + +请确保你的应用有[测试](../tutorial/testing.md){.internal-link target=_blank},并在持续集成(CI)中运行它们。 + +这样你就可以升级并确保一切仍按预期工作。 + +## `bump-pydantic` { #bump-pydantic } + +在很多情况下,如果你使用的是未做自定义的常规 Pydantic 模型,可以将从 Pydantic v1 迁移到 v2 的大部分过程自动化。 + +你可以使用同一 Pydantic 团队提供的 `bump-pydantic`。 + +该工具会帮助你自动修改大部分需要变更的代码。 + +之后运行测试检查是否一切正常。如果正常,你就完成了。😎 + +## 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。🚶 diff --git a/docs/zh/docs/how-to/separate-openapi-schemas.md b/docs/zh/docs/how-to/separate-openapi-schemas.md new file mode 100644 index 000000000..c3efe5f1a --- /dev/null +++ b/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` 字段没有**红色星号**,也就是未被标记为必填: + +
+ +
+ +### 输出用的模型 { #model-for-output } + +但如果你把同一个模型用作输出,例如: + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *} + +...那么因为 `description` 有默认值,即使你**不返回该字段**,它仍然会有这个**默认值**。 + +### 输出响应数据的模型 { #model-for-output-response-data } + +如果你在文档中交互并查看响应,即使代码没有给某个 `description` 字段赋值,JSON 响应中仍包含默认值(`null`): + +
+ +
+ +这意味着它**总会有值**,只是有时该值可能为 `None`(在 JSON 中是 `null`)。 + +这也意味着,使用你的 API 的客户端无需检查该值是否存在,他们可以**假设该字段总会存在**,只是有时它会是默认值 `None`。 + +在 OpenAPI 中描述这一点的方式,是把该字段标记为**必填**,因为它总会存在。 + +因此,一个模型的 JSON Schema 会根据它用于**输入还是输出**而有所不同: + +- 用于**输入**时,`description` **不是必填** +- 用于**输出**时,它是**必填**(并且可能为 `None`,在 JSON 中为 `null`) + +### 文档中的输出模型 { #model-for-output-in-docs } + +你也可以在文档中查看输出模型,`name` 和 `description` **都**被**红色星号**标记为**必填**: + +
+ +
+ +### 文档中的输入/输出模型 { #model-for-input-and-output-in-docs } + +如果你查看 OpenAPI 中可用的所有 Schema(JSON Schema),你会看到有两个,一个是 `Item-Input`,一个是 `Item-Output`。 + +对于 `Item-Input`,`description` **不是必填**,没有红色星号。 + +但对于 `Item-Output`,`description` 是**必填**,带有红色星号。 + +
+ +
+ +借助 **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` **不是必填**: + +
+ +
diff --git a/docs/zh/docs/how-to/testing-database.md b/docs/zh/docs/how-to/testing-database.md new file mode 100644 index 000000000..e4a20d843 --- /dev/null +++ b/docs/zh/docs/how-to/testing-database.md @@ -0,0 +1,7 @@ +# 测试数据库 { #testing-a-database } + +你可以在 SQLModel 文档 中学习数据库、SQL 和 SQLModel。🤓 + +这里有一个关于在 FastAPI 中使用 SQLModel 的小教程:使用 SQLModel 搭配 FastAPI 的教程。✨ + +该教程包含一个关于 测试 SQL 数据库 的章节。😎 diff --git a/docs/zh/docs/resources/index.md b/docs/zh/docs/resources/index.md new file mode 100644 index 000000000..2f55ac06f --- /dev/null +++ b/docs/zh/docs/resources/index.md @@ -0,0 +1,3 @@ +# 资源 { #resources } + +更多资源、外部链接等。✈️ diff --git a/docs/zh/docs/translation-banner.md b/docs/zh/docs/translation-banner.md new file mode 100644 index 000000000..76db203b0 --- /dev/null +++ b/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) + +///