diff --git a/docs/zh/docs/advanced/additional-responses.md b/docs/zh/docs/advanced/additional-responses.md
new file mode 100644
index 0000000000000..c76a92f238c37
--- /dev/null
+++ b/docs/zh/docs/advanced/additional-responses.md
@@ -0,0 +1,240 @@
+# Additional Responses in OpenAPI
+
+!!! warning
+ This is a rather advanced topic.
+
+ If you are starting with **FastAPI**, you might not need this.
+
+You can declare additional responses, with additional status codes, media types, descriptions, etc.
+
+Those additional responses will be included in the OpenAPI schema, so they will also appear in the API docs.
+
+But for those additional responses you have to make sure you return a `Response` like `JSONResponse` directly, with your status code and content.
+
+## Additional Response with `model`
+
+You can pass to your *path operation decorators* a parameter `responses`.
+
+It receives a `dict`, the keys are status codes for each response, like `200`, and the values are other `dict`s with the information for each of them.
+
+Each of those response `dict`s can have a key `model`, containing a Pydantic model, just like `response_model`.
+
+**FastAPI** will take that model, generate its JSON Schema and include it in the correct place in OpenAPI.
+
+For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
+
+```Python hl_lines="18 22"
+{!../../../docs_src/additional_responses/tutorial001.py!}
+```
+
+!!! note
+ Have in mind that you have to return the `JSONResponse` directly.
+
+!!! info
+ The `model` key is not part of OpenAPI.
+
+ **FastAPI** will take the Pydantic model from there, generate the `JSON Schema`, and put it in the correct place.
+
+ The correct place is:
+
+ * In the key `content`, that has as value another JSON object (`dict`) that contains:
+ * A key with the media type, e.g. `application/json`, that contains as value another JSON object, that contains:
+ * A key `schema`, that has as the value the JSON Schema from the model, here's the correct place.
+ * **FastAPI** adds a reference here to the global JSON Schemas in another place in your OpenAPI instead of including it directly. This way, other applications and clients can use those JSON Schemas directly, provide better code generation tools, etc.
+
+The generated responses in the OpenAPI for this *path operation* will be:
+
+```JSON hl_lines="3-12"
+{
+ "responses": {
+ "404": {
+ "description": "Additional Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Message"
+ }
+ }
+ }
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Item"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+The schemas are referenced to another place inside the OpenAPI schema:
+
+```JSON hl_lines="4-16"
+{
+ "components": {
+ "schemas": {
+ "Message": {
+ "title": "Message",
+ "required": [
+ "message"
+ ],
+ "type": "object",
+ "properties": {
+ "message": {
+ "title": "Message",
+ "type": "string"
+ }
+ }
+ },
+ "Item": {
+ "title": "Item",
+ "required": [
+ "id",
+ "value"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "title": "Id",
+ "type": "string"
+ },
+ "value": {
+ "title": "Value",
+ "type": "string"
+ }
+ }
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": [
+ "loc",
+ "msg",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "msg": {
+ "title": "Message",
+ "type": "string"
+ },
+ "type": {
+ "title": "Error Type",
+ "type": "string"
+ }
+ }
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+## Additional media types for the main response
+
+You can use this same `responses` parameter to add different media types for the same main response.
+
+For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:
+
+```Python hl_lines="19-24 28"
+{!../../../docs_src/additional_responses/tutorial002.py!}
+```
+
+!!! note
+ Notice that you have to return the image using a `FileResponse` directly.
+
+!!! info
+ Unless you specify a different media type explicitly in your `responses` parameter, FastAPI will assume the response has the same media type as the main response class (default `application/json`).
+
+ But if you have specified a custom response class with `None` as its media type, FastAPI will use `application/json` for any additional response that has an associated model.
+
+## Combining information
+
+You can also combine response information from multiple places, including the `response_model`, `status_code`, and `responses` parameters.
+
+You can declare a `response_model`, using the default status code `200` (or a custom one if you need), and then declare additional information for that same response in `responses`, directly in the OpenAPI schema.
+
+**FastAPI** will keep the additional information from `responses`, and combine it with the JSON Schema from your model.
+
+For example, you can declare a response with a status code `404` that uses a Pydantic model and has a custom `description`.
+
+And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
+
+```Python hl_lines="20-31"
+{!../../../docs_src/additional_responses/tutorial003.py!}
+```
+
+It will all be combined and included in your OpenAPI, and shown in the API docs:
+
+
+
+## Combine predefined responses and custom ones
+
+You might want to have some predefined responses that apply to many *path operations*, but you want to combine them with custom responses needed by each *path operation*.
+
+For those cases, you can use the Python technique of "unpacking" a `dict` with `**dict_to_unpack`:
+
+```Python
+old_dict = {
+ "old key": "old value",
+ "second old key": "second old value",
+}
+new_dict = {**old_dict, "new key": "new value"}
+```
+
+Here, `new_dict` will contain all the key-value pairs from `old_dict` plus the new key-value pair:
+
+```Python
+{
+ "old key": "old value",
+ "second old key": "second old value",
+ "new key": "new value",
+}
+```
+
+You can use that technique to re-use some predefined responses in your *path operations* and combine them with additional custom ones.
+
+For example:
+
+```Python hl_lines="13-17 26"
+{!../../../docs_src/additional_responses/tutorial004.py!}
+```
+
+## More information about OpenAPI responses
+
+To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:
+
+* OpenAPI Responses Object, it includes the `Response Object`.
+* OpenAPI Response Object, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
diff --git a/docs/zh/docs/advanced/additional-status-codes.md b/docs/zh/docs/advanced/additional-status-codes.md
index 54ec9775b6204..9981a8c7b5eec 100644
--- a/docs/zh/docs/advanced/additional-status-codes.md
+++ b/docs/zh/docs/advanced/additional-status-codes.md
@@ -10,25 +10,61 @@
例如,假设你想有一个 *路径操作* 能够更新条目,并且更新成功时返回 200 「成功」 的 HTTP 状态码。
-但是你也希望它能够接受新的条目。并且当这些条目不存在时,会自动创建并返回 201 「创建」的 HTTP 状态码。
+但是你也希望它能够接受新的条目。 并且当这些条目不存在时,会自动创建并返回 201 「创建」的 HTTP 状态码。
要实现它,导入 `JSONResponse`,然后在其中直接返回你的内容,并将 `status_code` 设置为为你要的值。
-```Python hl_lines="4 25"
-{!../../../docs_src/additional_status_codes/tutorial001.py!}
-```
+=== "Python 3.10+"
-!!! warning "警告"
- 当你直接返回一个像上面例子中的 `Response` 对象时,它会直接返回。
+ ```Python hl_lines="4 25"
+ !!! note "技术细节"
+ 你也可以使用 from starlette.responses import JSONResponse。
+ ```
+。
+
- FastAPI 不会用模型等对该响应进行序列化。
+=== "Python 3.9+"
- 确保其中有你想要的数据,且返回的值为合法的 JSON(如果你使用 `JSONResponse` 的话)。
+ ```Python hl_lines="4 25"
+ !!! warning "警告"
+ 当你直接返回一个像上面例子中的 Response 对象时,它会直接返回。
+ ```
+ 对象时,它会直接返回。
+
-!!! note "技术细节"
- 你也可以使用 `from starlette.responses import JSONResponse`。
+=== "Python 3.6+"
- 出于方便,**FastAPI** 为开发者提供同 `starlette.responses` 一样的 `fastapi.responses`。但是大多数可用的响应都是直接来自 Starlette。`status` 也是一样。
+ ```Python hl_lines="4 26"
+ {!> ../../../docs_src/additional_status_codes/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 23"
+ {!> ../../../docs_src/additional_status_codes/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 25"
+ {!../../../docs_src/additional_status_codes/tutorial001.py!}
+ ```
+
+!!! warning
+ When you return a `Response` directly, like in the example above, it will be returned directly.
+
+ FastAPI 不会用模型等对该响应进行序列化。 确保其中有你想要的数据,且返回的值为合法的 JSON(如果你使用 `JSONResponse` 的话)。
+
+!!! note "Technical Details"
+ You could also use `from starlette.responses import JSONResponse`.
+
+ 出于方便,**FastAPI** 为开发者提供同 `starlette.responses` 一样的 `fastapi.responses`。 但是大多数可用的响应都是直接来自 Starlette。 `status` 也是一样。
## OpenAPI 和 API 文档
diff --git a/docs/zh/docs/advanced/advanced-dependencies.md b/docs/zh/docs/advanced/advanced-dependencies.md
new file mode 100644
index 0000000000000..845713c30a966
--- /dev/null
+++ b/docs/zh/docs/advanced/advanced-dependencies.md
@@ -0,0 +1,138 @@
+# Advanced Dependencies
+
+## Parameterized dependencies
+
+All the dependencies we have seen are a fixed function or class.
+
+But there could be cases where you want to be able to set parameters on the dependency, without having to declare many different functions or classes.
+
+Let's imagine that we want to have a dependency that checks if the query parameter `q` contains some fixed content.
+
+But we want to be able to parameterize that fixed content.
+
+## A "callable" instance
+
+In Python there's a way to make an instance of a class a "callable".
+
+Not the class itself (which is already a callable), but an instance of that class.
+
+To do that, we declare a method `__call__`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/dependencies/tutorial011_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/dependencies/tutorial011.py!}
+ ```
+
+In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.
+
+## Parameterize the instance
+
+And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/dependencies/tutorial011_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/dependencies/tutorial011.py!}
+ ```
+
+In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
+
+## Create an instance
+
+We could create an instance of this class with:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial011_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/dependencies/tutorial011.py!}
+ ```
+
+And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
+
+## Use the instance as a dependency
+
+Then, we could use this `checker` in a `Depends(checker)`, instead of `Depends(FixedContentQueryChecker)`, because the dependency is the instance, `checker`, not the class itself.
+
+And when solving the dependency, **FastAPI** will call this `checker` like:
+
+```Python
+checker(q="somequery")
+```
+
+...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/dependencies/tutorial011_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/dependencies/tutorial011.py!}
+ ```
+
+!!! tip
+ All this might seem contrived. And it might not be very clear how is it useful yet.
+
+ These examples are intentionally simple, but show how it all works.
+
+ In the chapters about security, there are utility functions that are implemented in this same way.
+
+ If you understood all this, you already know how those utility tools for security work underneath.
diff --git a/docs/zh/docs/advanced/async-sql-databases.md b/docs/zh/docs/advanced/async-sql-databases.md
new file mode 100644
index 0000000000000..6a85f2237ea1f
--- /dev/null
+++ b/docs/zh/docs/advanced/async-sql-databases.md
@@ -0,0 +1,169 @@
+# Async SQL (Relational) Databases
+
+!!! info
+ These docs are about to be updated. 🎉
+
+ The current version assumes Pydantic v1.
+
+ The new docs will include Pydantic v2 and will use SQLModel once it is updated to use Pydantic v2 as well.
+
+You can also use `encode/databases` with **FastAPI** to connect to databases using `async` and `await`.
+
+It is compatible with:
+
+* PostgreSQL
+* MySQL
+* SQLite
+
+In this example, we'll use **SQLite**, because it uses a single file and Python has integrated support. So, you can copy this example and run it as is.
+
+Later, for your production application, you might want to use a database server like **PostgreSQL**.
+
+!!! tip
+ You could adopt ideas from the section about SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), like using utility functions to perform operations in the database, independent of your **FastAPI** code.
+
+ This section doesn't apply those ideas, to be equivalent to the counterpart in Starlette.
+
+## Import and set up `SQLAlchemy`
+
+* Import `SQLAlchemy`.
+* Create a `metadata` object.
+* Create a table `notes` using the `metadata` object.
+
+```Python hl_lines="4 14 16-22"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+!!! tip
+ Notice that all this code is pure SQLAlchemy Core.
+
+ `databases` is not doing anything here yet.
+
+## Import and set up `databases`
+
+* Import `databases`.
+* Create a `DATABASE_URL`.
+* Create a `database` object.
+
+```Python hl_lines="3 9 12"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+!!! tip
+ If you were connecting to a different database (e.g. PostgreSQL), you would need to change the `DATABASE_URL`.
+
+## Create the tables
+
+In this case, we are creating the tables in the same Python file, but in production, you would probably want to create them with Alembic, integrated with migrations, etc.
+
+Here, this section would run directly, right before starting your **FastAPI** application.
+
+* Create an `engine`.
+* Create all the tables from the `metadata` object.
+
+```Python hl_lines="25-28"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+## Create models
+
+Create Pydantic models for:
+
+* Notes to be created (`NoteIn`).
+* Notes to be returned (`Note`).
+
+```Python hl_lines="31-33 36-39"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+By creating these Pydantic models, the input data will be validated, serialized (converted), and annotated (documented).
+
+So, you will be able to see it all in the interactive API docs.
+
+## Connect and disconnect
+
+* Create your `FastAPI` application.
+* Create event handlers to connect and disconnect from the database.
+
+```Python hl_lines="42 45-47 50-52"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+## Read notes
+
+Create the *path operation function* to read notes:
+
+```Python hl_lines="55-58"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+!!! Note
+ Notice that as we communicate with the database using `await`, the *path operation function* is declared with `async`.
+
+### Notice the `response_model=List[Note]`
+
+It uses `typing.List`.
+
+That documents (and validates, serializes, filters) the output data, as a `list` of `Note`s.
+
+## Create notes
+
+Create the *path operation function* to create notes:
+
+```Python hl_lines="61-65"
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
+```
+
+!!! Note
+ Notice that as we communicate with the database using `await`, the *path operation function* is declared with `async`.
+
+### About `{**note.dict(), "id": last_record_id}`
+
+`note` is a Pydantic `Note` object.
+
+`note.dict()` returns a `dict` with its data, something like:
+
+```Python
+{
+ "text": "Some note",
+ "completed": False,
+}
+```
+
+but it doesn't have the `id` field.
+
+So we create a new `dict`, that contains the key-value pairs from `note.dict()` with:
+
+```Python
+{**note.dict()}
+```
+
+`**note.dict()` "unpacks" the key value pairs directly, so, `{**note.dict()}` would be, more or less, a copy of `note.dict()`.
+
+And then, we extend that copy `dict`, adding another key-value pair: `"id": last_record_id`:
+
+```Python
+{**note.dict(), "id": last_record_id}
+```
+
+So, the final result returned would be something like:
+
+```Python
+{
+ "id": 1,
+ "text": "Some note",
+ "completed": False,
+}
+```
+
+## Check it
+
+You can copy this code as is, and see the docs at http://127.0.0.1:8000/docs.
+
+There you can see all your API documented and interact with it:
+
+
+
+## More info
+
+You can read more about `encode/databases` at its GitHub page.
diff --git a/docs/zh/docs/advanced/async-tests.md b/docs/zh/docs/advanced/async-tests.md
new file mode 100644
index 0000000000000..9b39d70fca6a8
--- /dev/null
+++ b/docs/zh/docs/advanced/async-tests.md
@@ -0,0 +1,92 @@
+# Async Tests
+
+You have already seen how to test your **FastAPI** applications using the provided `TestClient`. Up to now, you have only seen how to write synchronous tests, without using `async` functions.
+
+Being able to use asynchronous functions in your tests could be useful, for example, when you're querying your database asynchronously. Imagine you want to test sending requests to your FastAPI application and then verify that your backend successfully wrote the correct data in the database, while using an async database library.
+
+Let's look at how we can make that work.
+
+## pytest.mark.anyio
+
+If we want to call asynchronous functions in our tests, our test functions have to be asynchronous. AnyIO provides a neat plugin for this, that allows us to specify that some test functions are to be called asynchronously.
+
+## HTTPX
+
+Even if your **FastAPI** application uses normal `def` functions instead of `async def`, it is still an `async` application underneath.
+
+The `TestClient` does some magic inside to call the asynchronous FastAPI application in your normal `def` test functions, using standard pytest. But that magic doesn't work anymore when we're using it inside asynchronous functions. By running our tests asynchronously, we can no longer use the `TestClient` inside our test functions.
+
+The `TestClient` is based on HTTPX, and luckily, we can use it directly to test the API.
+
+## Example
+
+For a simple example, let's consider a file structure similar to the one described in [Bigger Applications](../tutorial/bigger-applications.md){.internal-link target=_blank} and [Testing](../tutorial/testing.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+The file `main.py` would have:
+
+```Python
+{!../../../docs_src/async_tests/main.py!}
+```
+
+The file `test_main.py` would have the tests for `main.py`, it could look like this now:
+
+```Python
+{!../../../docs_src/async_tests/test_main.py!}
+```
+
+## Run it
+
+You can run your tests as usual via:
+
+
+
+But if we access the docs UI at the "official" URL using the proxy with port `9999`, at `/api/v1/docs`, it works correctly! 🎉
+
+You can check it at http://127.0.0.1:9999/api/v1/docs:
+
+
+
+Right as we wanted it. ✔️
+
+This is because FastAPI uses this `root_path` to create the default `server` in OpenAPI with the URL provided by `root_path`.
+
+## Additional servers
+
+!!! warning
+ This is a more advanced use case. Feel free to skip it.
+
+By default, **FastAPI** will create a `server` in the OpenAPI schema with the URL for the `root_path`.
+
+But you can also provide other alternative `servers`, for example if you want *the same* docs UI to interact with a staging and production environments.
+
+If you pass a custom list of `servers` and there's a `root_path` (because your API lives behind a proxy), **FastAPI** will insert a "server" with this `root_path` at the beginning of the list.
+
+For example:
+
+```Python hl_lines="4-7"
+{!../../../docs_src/behind_a_proxy/tutorial003.py!}
+```
+
+Will generate an OpenAPI schema like:
+
+```JSON hl_lines="5-7"
+{
+ "openapi": "3.1.0",
+ // More stuff here
+ "servers": [
+ {
+ "url": "/api/v1"
+ },
+ {
+ "url": "https://stag.example.com",
+ "description": "Staging environment"
+ },
+ {
+ "url": "https://prod.example.com",
+ "description": "Production environment"
+ }
+ ],
+ "paths": {
+ // More stuff here
+ }
+}
+```
+
+!!! tip
+ Notice the auto-generated server with a `url` value of `/api/v1`, taken from the `root_path`.
+
+In the docs UI at http://127.0.0.1:9999/api/v1/docs it would look like:
+
+
+
+!!! tip
+ The docs UI will interact with the server that you select.
+
+### Disable automatic server from `root_path`
+
+If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:
+
+```Python hl_lines="9"
+{!../../../docs_src/behind_a_proxy/tutorial004.py!}
+```
+
+and then it won't include it in the OpenAPI schema.
+
+## Mounting a sub-application
+
+If you need to mount a sub-application (as described in [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}) while also using a proxy with `root_path`, you can do it normally, as you would expect.
+
+FastAPI will internally use the `root_path` smartly, so it will just work. ✨
diff --git a/docs/zh/docs/advanced/conditional-openapi.md b/docs/zh/docs/advanced/conditional-openapi.md
new file mode 100644
index 0000000000000..add16fbec519e
--- /dev/null
+++ b/docs/zh/docs/advanced/conditional-openapi.md
@@ -0,0 +1,58 @@
+# Conditional OpenAPI
+
+If you needed to, you could use settings and environment variables to configure OpenAPI conditionally depending on the environment, and even disable it entirely.
+
+## About security, APIs, and docs
+
+Hiding your documentation user interfaces in production *shouldn't* be the way to protect your API.
+
+That doesn't add any extra security to your API, the *path operations* will still be available where they are.
+
+If there's a security flaw in your code, it will still exist.
+
+Hiding the documentation just makes it more difficult to understand how to interact with your API, and could make it more difficult for you to debug it in production. It could be considered simply a form of Security through obscurity.
+
+If you want to secure your API, there are several better things you can do, for example:
+
+* Make sure you have well defined Pydantic models for your request bodies and responses.
+* Configure any required permissions and roles using dependencies.
+* Never store plaintext passwords, only password hashes.
+* Implement and use well-known cryptographic tools, like Passlib and JWT tokens, etc.
+* Add more granular permission controls with OAuth2 scopes where needed.
+* ...etc.
+
+Nevertheless, you might have a very specific use case where you really need to disable the API docs for some environment (e.g. for production) or depending on configurations from environment variables.
+
+## Conditional OpenAPI from settings and env vars
+
+You can easily use the same Pydantic settings to configure your generated OpenAPI and the docs UIs.
+
+For example:
+
+```Python hl_lines="6 11"
+{!../../../docs_src/conditional_openapi/tutorial001.py!}
+```
+
+Here we declare the setting `openapi_url` with the same default of `"/openapi.json"`.
+
+And then we use it when creating the `FastAPI` app.
+
+Then you could disable OpenAPI (including the UI docs) by setting the environment variable `OPENAPI_URL` to the empty string, like:
+
+
+
## 可用响应
@@ -99,10 +104,10 @@
要记得你可以使用 `Response` 来返回任何其他东西,甚至创建一个自定义的子类。
-!!! note "技术细节"
- 你也可以使用 `from starlette.responses import HTMLResponse`。
+!!! note "Technical Details"
+ You could also use `from starlette.responses import HTMLResponse`.
- **FastAPI** 提供了同 `fastapi.responses` 相同的 `starlette.responses` 只是为了方便开发者。但大多数可用的响应都直接来自 Starlette。
+ **FastAPI** 提供了同 `fastapi.responses` 相同的 `starlette.responses` 只是为了方便开发者。 但大多数可用的响应都直接来自 Starlette。
### `Response`
@@ -110,15 +115,14 @@
你可以直接返回它。
-`Response` 类接受如下参数:
+It accepts the following parameters:
* `content` - 一个 `str` 或者 `bytes`。
* `status_code` - 一个 `int` 类型的 HTTP 状态码。
* `headers` - 一个由字符串组成的 `dict`。
-* `media_type` - 一个给出媒体类型的 `str`,比如 `"text/html"`。
-
-FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它还将包含一个基于 media_type 的 Content-Type 头,并为文本类型附加一个字符集。
+* `media_type` - A `str` giving the media type. E.g. `"text/html"`.
+FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。 它还将包含一个基于 media_type 的 Content-Type 头,并为文本类型附加一个字符集。
```Python hl_lines="1 18"
{!../../../docs_src/response_directly/tutorial002.py!}
@@ -146,29 +150,53 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
如上文所述,`ORJSONResponse` 是一个使用 `orjson` 的快速的可选 JSON 响应。
-
### `UJSONResponse`
`UJSONResponse` 是一个使用 `ujson` 的可选 JSON 响应。
-!!! warning "警告"
+!!! !!! warning "警告"
在处理某些边缘情况时,`ujson` 不如 Python 的内置实现那么谨慎。
-```Python hl_lines="2 7"
+```Python hl_lines="2 7"
{!../../../docs_src/custom_response/tutorial001.py!}
```
-!!! tip "小贴士"
- `ORJSONResponse` 可能是一个更快的选择。
+!!! tip
+ It's possible that `ORJSONResponse` might be a faster alternative.
### `RedirectResponse`
-返回 HTTP 重定向。默认情况下使用 307 状态代码(临时重定向)。
+返回 HTTP 重定向。 默认情况下使用 307 状态代码(临时重定向)。
+
+!!! note "技术细节"
+ 你也可以使用 `from starlette.responses import HTMLResponse`。
```Python hl_lines="2 9"
{!../../../docs_src/custom_response/tutorial006.py!}
```
+---
+
+!!! info "提示"
+ 参数 `response_class` 也会用来定义响应的「媒体类型」。
+
+
+```Python hl_lines="2 7 9"
+{!../../../docs_src/custom_response/tutorial006b.py!}
+```
+
+If you do that, then you can return the URL directly from your *path operation* function.
+
+In this case, the `status_code` used will be the default one for the `RedirectResponse`, which is `307`.
+
+---
+
+`media_type` - 一个给出媒体类型的 `str`,比如 `"text/html"`。
+
+```Python hl_lines="2 7 9"
+{!../../../docs_src/custom_response/tutorial006c.py!}
+```
+
### `StreamingResponse`
采用异步生成器或普通生成器/迭代器,然后流式传输响应主体。
@@ -181,13 +209,23 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
如果您有类似文件的对象(例如,由 `open()` 返回的对象),则可以在 `StreamingResponse` 中将其返回。
+That way, you don't have to read it all first in memory, and you can pass that generator function to the `StreamingResponse`, and return it.
+
包括许多与云存储,视频处理等交互的库。
-```Python hl_lines="2 10-12 14"
+```{ .python .annotate hl_lines="2 10-12 14" }
{!../../../docs_src/custom_response/tutorial008.py!}
```
-!!! tip "小贴士"
+1. This is the generator function. It's a "generator function" because it contains `yield` statements inside.
+2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response.
+3. This `yield from` tells the function to iterate over that thing named `file_like`. And then, for each part iterated, yield that part as coming from this generator function.
+
+ So, it is a generator function that transfers the "generating" work to something else internally.
+
+ By doing it this way, we can put it in a `with` block, and that way, ensure that it is closed after finishing.
+
+!!! !!! tip "小贴士"
注意在这里,因为我们使用的是不支持 `async` 和 `await` 的标准 `open()`,我们使用普通的 `def` 声明了路径操作。
### `FileResponse`
@@ -198,7 +236,7 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
* `path` - 要流式传输的文件的文件路径。
* `headers` - 任何自定义响应头,传入字典类型。
-* `media_type` - 给出媒体类型的字符串。如果未设置,则文件名或路径将用于推断媒体类型。
+* `media_type` - 给出媒体类型的字符串。 如果未设置,则文件名或路径将用于推断媒体类型。
* `filename` - 如果给出,它将包含在响应的 `Content-Disposition` 中。
文件响应将包含适当的 `Content-Length`,`Last-Modified` 和 `ETag` 的响应头。
@@ -207,6 +245,64 @@ FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它
{!../../../docs_src/custom_response/tutorial009.py!}
```
+`Response` 类接受如下参数:
+
+```Python hl_lines="2 8 10"
+{!../../../docs_src/custom_response/tutorial009b.py!}
+```
+
+In this case, you can return the file path directly from your *path operation* function.
+
+## Custom response class
+
+!!! info "提示"
+ 当然,实际的 `Content-Type` 头,状态码等等,将来自于你返回的 `Response` 对象。
+
+!!! tip "小贴士"
+ `ORJSONResponse` 可能是一个更快的选择。
+
+Let's say you want it to return indented and formatted JSON, so you want to use the orjson option `orjson.OPT_INDENT_2`.
+
+You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`:
+
+```Python hl_lines="9-14 17"
+{!../../../docs_src/custom_response/tutorial009c.py!}
+```
+
+Now instead of returning:
+
+```json
+{"message": "Hello World"}
+```
+
+...this response will return:
+
+```json
+{
+ "message": "Hello World"
+}
+```
+
+Of course, you will probably find much better ways to take advantage of this than formatting JSON. 😉
+
+## Default response class
+
+!!! note "说明"
+ 如果你使用不带有任何媒体类型的响应类,FastAPI 认为你的响应没有任何内容,所以不会在生成的OpenAPI文档中记录响应格式。
+
+!!! info "提示"
+ 参数 `response_class` 也会用来定义响应的「媒体类型」。
+
+!!! tip "小贴士"
+ `ORJSONResponse` 目前只在 FastAPI 中可用,而在 Starlette 中不可用。
+
+```Python hl_lines="2 4"
+{!../../../docs_src/custom_response/tutorial010.py!}
+```
+
+!!! tip
+ You can still override `response_class` in *path operations* as before.
+
## 额外文档
您还可以使用 `response` 在 OpenAPI 中声明媒体类型和许多其他详细信息:[OpenAPI 中的额外文档](additional-responses.md){.internal-link target=_blank}。
diff --git a/docs/zh/docs/advanced/dataclasses.md b/docs/zh/docs/advanced/dataclasses.md
new file mode 100644
index 0000000000000..fe6b740aa391a
--- /dev/null
+++ b/docs/zh/docs/advanced/dataclasses.md
@@ -0,0 +1,98 @@
+# Using Dataclasses
+
+FastAPI is built on top of **Pydantic**, and I have been showing you how to use Pydantic models to declare requests and responses.
+
+But FastAPI also supports using `dataclasses` the same way:
+
+```Python hl_lines="1 7-12 19-20"
+{!../../../docs_src/dataclasses/tutorial001.py!}
+```
+
+This is still supported thanks to **Pydantic**, as it has internal support for `dataclasses`.
+
+So, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses.
+
+And of course, it supports the same:
+
+* data validation
+* data serialization
+* data documentation, etc.
+
+This works the same way as with Pydantic models. And it is actually achieved in the same way underneath, using Pydantic.
+
+!!! info
+ Have in mind that dataclasses can't do everything Pydantic models can do.
+
+ So, you might still need to use Pydantic models.
+
+ But if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. 🤓
+
+## Dataclasses in `response_model`
+
+You can also use `dataclasses` in the `response_model` parameter:
+
+```Python hl_lines="1 7-13 19"
+{!../../../docs_src/dataclasses/tutorial002.py!}
+```
+
+The dataclass will be automatically converted to a Pydantic dataclass.
+
+This way, its schema will show up in the API docs user interface:
+
+
+
+## Dataclasses in Nested Data Structures
+
+You can also combine `dataclasses` with other type annotations to make nested data structures.
+
+In some cases, you might still have to use Pydantic's version of `dataclasses`. For example, if you have errors with the automatically generated API documentation.
+
+In that case, you can simply swap the standard `dataclasses` with `pydantic.dataclasses`, which is a drop-in replacement:
+
+```{ .python .annotate hl_lines="1 5 8-11 14-17 23-25 28" }
+{!../../../docs_src/dataclasses/tutorial003.py!}
+```
+
+1. We still import `field` from standard `dataclasses`.
+
+2. `pydantic.dataclasses` is a drop-in replacement for `dataclasses`.
+
+3. The `Author` dataclass includes a list of `Item` dataclasses.
+
+4. The `Author` dataclass is used as the `response_model` parameter.
+
+5. You can use other standard type annotations with dataclasses as the request body.
+
+ In this case, it's a list of `Item` dataclasses.
+
+6. Here we are returning a dictionary that contains `items` which is a list of dataclasses.
+
+ FastAPI is still capable of serializing the data to JSON.
+
+7. Here the `response_model` is using a type annotation of a list of `Author` dataclasses.
+
+ Again, you can combine `dataclasses` with standard type annotations.
+
+8. Notice that this *path operation function* uses regular `def` instead of `async def`.
+
+ As always, in FastAPI you can combine `def` and `async def` as needed.
+
+ If you need a refresher about when to use which, check out the section _"In a hurry?"_ in the docs about `async` and `await`.
+
+9. This *path operation function* is not returning dataclasses (although it could), but a list of dictionaries with internal data.
+
+ FastAPI will use the `response_model` parameter (that includes dataclasses) to convert the response.
+
+You can combine `dataclasses` with other type annotations in many different combinations to form complex data structures.
+
+Check the in-code annotation tips above to see more specific details.
+
+## Learn More
+
+You can also combine `dataclasses` with other Pydantic models, inherit from them, include them in your own models, etc.
+
+To learn more, check the Pydantic docs about dataclasses.
+
+## Version
+
+This is available since FastAPI version `0.67.0`. 🔖
diff --git a/docs/zh/docs/advanced/events.md b/docs/zh/docs/advanced/events.md
new file mode 100644
index 0000000000000..f62743b798255
--- /dev/null
+++ b/docs/zh/docs/advanced/events.md
@@ -0,0 +1,162 @@
+# Lifespan Events
+
+You can define logic (code) that should be executed before the application **starts up**. This means that this code will be executed **once**, **before** the application **starts receiving requests**.
+
+The same way, you can define logic (code) that should be executed when the application is **shutting down**. In this case, this code will be executed **once**, **after** having handled possibly **many requests**.
+
+Because this code is executed before the application **starts** taking requests, and right after it **finishes** handling requests, it covers the whole application **lifespan** (the word "lifespan" will be important in a second 😉).
+
+This can be very useful for setting up **resources** that you need to use for the whole app, and that are **shared** among requests, and/or that you need to **clean up** afterwards. For example, a database connection pool, or loading a shared machine learning model.
+
+## Use Case
+
+Let's start with an example **use case** and then see how to solve it with this.
+
+Let's imagine that you have some **machine learning models** that you want to use to handle requests. 🤖
+
+The same models are shared among requests, so, it's not one model per request, or one per user or something similar.
+
+Let's imagine that loading the model can **take quite some time**, because it has to read a lot of **data from disk**. So you don't want to do it for every request.
+
+You could load it at the top level of the module/file, but that would also mean that it would **load the model** even if you are just running a simple automated test, then that test would be **slow** because it would have to wait for the model to load before being able to run an independent part of the code.
+
+That's what we'll solve, let's load the model before the requests are handled, but only right before the application starts receiving requests, not while the code is being loaded.
+
+## Lifespan
+
+You can define this *startup* and *shutdown* logic using the `lifespan` parameter of the `FastAPI` app, and a "context manager" (I'll show you what that is in a second).
+
+Let's start with an example and then see it in detail.
+
+We create an async function `lifespan()` with `yield` like this:
+
+```Python hl_lines="16 19"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*.
+
+And then, right after the `yield`, we unload the model. This code will be executed **after** the application **finishes handling requests**, right before the *shutdown*. This could, for example, release resources like memory or a GPU.
+
+!!! tip
+ The `shutdown` would happen when you are **stopping** the application.
+
+ Maybe you need to start a new version, or you just got tired of running it. 🤷
+
+### Lifespan function
+
+The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`.
+
+```Python hl_lines="14-19"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+The first part of the function, before the `yield`, will be executed **before** the application starts.
+
+And the part after the `yield` will be executed **after** the application has finished.
+
+### Async Context Manager
+
+If you check, the function is decorated with an `@asynccontextmanager`.
+
+That converts the function into something called an "**async context manager**".
+
+```Python hl_lines="1 13"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager:
+
+```Python
+with open("file.txt") as file:
+ file.read()
+```
+
+In recent versions of Python, there's also an **async context manager**. You would use it with `async with`:
+
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+When you create a context manager or an async context manager like above, what it does is that, before entering the `with` block, it will execute the code before the `yield`, and after exiting the `with` block, it will execute the code after the `yield`.
+
+In our code example above, we don't use it directly, but we pass it to FastAPI for it to use it.
+
+The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it.
+
+```Python hl_lines="22"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+## Alternative Events (deprecated)
+
+!!! warning
+ The recommended way to handle the *startup* and *shutdown* is using the `lifespan` parameter of the `FastAPI` app as described above.
+
+ You can probably skip this part.
+
+There's an alternative way to define this logic to be executed during *startup* and during *shutdown*.
+
+You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.
+
+These functions can be declared with `async def` or normal `def`.
+
+### `startup` event
+
+To add a function that should be run before the application starts, declare it with the event `"startup"`:
+
+```Python hl_lines="8"
+{!../../../docs_src/events/tutorial001.py!}
+```
+
+In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
+
+You can add more than one event handler function.
+
+And your application won't start receiving requests until all the `startup` event handlers have completed.
+
+### `shutdown` event
+
+To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
+
+```Python hl_lines="6"
+{!../../../docs_src/events/tutorial002.py!}
+```
+
+Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.
+
+!!! info
+ In the `open()` function, the `mode="a"` means "append", so, the line will be added after whatever is on that file, without overwriting the previous contents.
+
+!!! tip
+ Notice that in this case we are using a standard Python `open()` function that interacts with a file.
+
+ So, it involves I/O (input/output), that requires "waiting" for things to be written to disk.
+
+ But `open()` doesn't use `async` and `await`.
+
+ So, we declare the event handler function with standard `def` instead of `async def`.
+
+### `startup` and `shutdown` together
+
+There's a high chance that the logic for your *startup* and *shutdown* is connected, you might want to start something and then finish it, acquire a resource and then release it, etc.
+
+Doing that in separated functions that don't share logic or variables together is more difficult as you would need to store values in global variables or similar tricks.
+
+Because of that, it's now recommended to instead use the `lifespan` as explained above.
+
+## Technical Details
+
+Just a technical detail for the curious nerds. 🤓
+
+Underneath, in the ASGI technical specification, this is part of the Lifespan Protocol, and it defines events called `startup` and `shutdown`.
+
+!!! info
+ You can read more about the Starlette `lifespan` handlers in Starlette's Lifespan' docs.
+
+ Including how to handle lifespan state that can be used in other areas of your code.
+
+## Sub Applications
+
+🚨 Have in mind that these lifespan events (startup and shutdown) will only be executed for the main application, not for [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}.
diff --git a/docs/zh/docs/advanced/extending-openapi.md b/docs/zh/docs/advanced/extending-openapi.md
new file mode 100644
index 0000000000000..fe3f649f93230
--- /dev/null
+++ b/docs/zh/docs/advanced/extending-openapi.md
@@ -0,0 +1,318 @@
+# Extending OpenAPI
+
+!!! warning
+ This is a rather advanced feature. You probably can skip it.
+
+ If you are just following the tutorial - user guide, you can probably skip this section.
+
+ If you already know that you need to modify the generated OpenAPI schema, continue reading.
+
+There are some cases where you might need to modify the generated OpenAPI schema.
+
+In this section you will see how.
+
+## The normal process
+
+The normal (default) process, is as follows.
+
+A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema.
+
+As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered.
+
+It just returns a JSON response with the result of the application's `.openapi()` method.
+
+By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them.
+
+If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`.
+
+And that function `get_openapi()` receives as parameters:
+
+* `title`: The OpenAPI title, shown in the docs.
+* `version`: The version of your API, e.g. `2.5.0`.
+* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`.
+* `summary`: A short summary of the API.
+* `description`: The description of your API, this can include markdown and will be shown in the docs.
+* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.
+
+!!! info
+ The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above.
+
+## Overriding the defaults
+
+Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
+
+For example, let's add ReDoc's OpenAPI extension to include a custom logo.
+
+### Normal **FastAPI**
+
+First, write all your **FastAPI** application as normally:
+
+```Python hl_lines="1 4 7-9"
+{!../../../docs_src/extending_openapi/tutorial001.py!}
+```
+
+### Generate the OpenAPI schema
+
+Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
+
+```Python hl_lines="2 15-21"
+{!../../../docs_src/extending_openapi/tutorial001.py!}
+```
+
+### Modify the OpenAPI schema
+
+Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
+
+```Python hl_lines="22-24"
+{!../../../docs_src/extending_openapi/tutorial001.py!}
+```
+
+### Cache the OpenAPI schema
+
+You can use the property `.openapi_schema` as a "cache", to store your generated schema.
+
+That way, your application won't have to generate the schema every time a user opens your API docs.
+
+It will be generated only once, and then the same cached schema will be used for the next requests.
+
+```Python hl_lines="13-14 25-26"
+{!../../../docs_src/extending_openapi/tutorial001.py!}
+```
+
+### Override the method
+
+Now you can replace the `.openapi()` method with your new function.
+
+```Python hl_lines="29"
+{!../../../docs_src/extending_openapi/tutorial001.py!}
+```
+
+### Check it
+
+Once you go to http://127.0.0.1:8000/redoc you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
+
+
+
+## Self-hosting JavaScript and CSS for docs
+
+The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files.
+
+By default, those files are served from a CDN.
+
+But it's possible to customize it, you can set a specific CDN, or serve the files yourself.
+
+That's useful, for example, if you need your app to keep working even while offline, without open Internet access, or in a local network.
+
+Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them.
+
+### Project file structure
+
+Let's say your project file structure looks like this:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+```
+
+Now create a directory to store those static files.
+
+Your new file structure could look like this:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static/
+```
+
+### Download the files
+
+Download the static files needed for the docs and put them on that `static/` directory.
+
+You can probably right-click each link and select an option similar to `Save link as...`.
+
+**Swagger UI** uses the files:
+
+* `swagger-ui-bundle.js`
+* `swagger-ui.css`
+
+And **ReDoc** uses the file:
+
+* `redoc.standalone.js`
+
+After that, your file structure could look like:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static
+ ├── redoc.standalone.js
+ ├── swagger-ui-bundle.js
+ └── swagger-ui.css
+```
+
+### Serve the static files
+
+* Import `StaticFiles`.
+* "Mount" a `StaticFiles()` instance in a specific path.
+
+```Python hl_lines="7 11"
+{!../../../docs_src/extending_openapi/tutorial002.py!}
+```
+
+### Test the static files
+
+Start your application and go to http://127.0.0.1:8000/static/redoc.standalone.js.
+
+You should see a very long JavaScript file for **ReDoc**.
+
+It could start with something like:
+
+```JavaScript
+/*!
+ * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
+ * -------------------------------------------------------------
+ * Version: "2.0.0-rc.18"
+ * Repo: https://github.com/Redocly/redoc
+ */
+!function(e,t){"object"==typeof exports&&"object"==typeof m
+
+...
+```
+
+That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place.
+
+Now we can configure the app to use those static files for the docs.
+
+### Disable the automatic docs
+
+The first step is to disable the automatic docs, as those use the CDN by default.
+
+To disable them, set their URLs to `None` when creating your `FastAPI` app:
+
+```Python hl_lines="9"
+{!../../../docs_src/extending_openapi/tutorial002.py!}
+```
+
+### Include the custom docs
+
+Now you can create the *path operations* for the custom docs.
+
+You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:
+
+* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`.
+* `title`: the title of your API.
+* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.
+* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the one that your own app is now serving.
+* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the one that your own app is now serving.
+
+And similarly for ReDoc...
+
+```Python hl_lines="2-6 14-22 25-27 30-36"
+{!../../../docs_src/extending_openapi/tutorial002.py!}
+```
+
+!!! tip
+ The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.
+
+ If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication.
+
+ Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper.
+
+### Create a *path operation* to test it
+
+Now, to be able to test that everything works, create a *path operation*:
+
+```Python hl_lines="39-41"
+{!../../../docs_src/extending_openapi/tutorial002.py!}
+```
+
+### Test it
+
+Now, you should be able to disconnect your WiFi, go to your docs at http://127.0.0.1:8000/docs, and reload the page.
+
+And even without Internet, you would be able to see the docs for your API and interact with it.
+
+## Configuring Swagger UI
+
+You can configure some extra Swagger UI parameters.
+
+To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function.
+
+`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly.
+
+FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs.
+
+### Disable Syntax Highlighting
+
+For example, you could disable syntax highlighting in Swagger UI.
+
+Without changing the settings, syntax highlighting is enabled by default:
+
+
+
+But you can disable it by setting `syntaxHighlight` to `False`:
+
+```Python hl_lines="3"
+{!../../../docs_src/extending_openapi/tutorial003.py!}
+```
+
+...and then Swagger UI won't show the syntax highlighting anymore:
+
+
+
+### Change the Theme
+
+The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
+
+```Python hl_lines="3"
+{!../../../docs_src/extending_openapi/tutorial004.py!}
+```
+
+That configuration would change the syntax highlighting color theme:
+
+
+
+### Change Default Swagger UI Parameters
+
+FastAPI includes some default configuration parameters appropriate for most of the use cases.
+
+It includes these default configurations:
+
+```Python
+{!../../../fastapi/openapi/docs.py[ln:7-13]!}
+```
+
+You can override any of them by setting a different value in the argument `swagger_ui_parameters`.
+
+For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
+
+```Python hl_lines="3"
+{!../../../docs_src/extending_openapi/tutorial005.py!}
+```
+
+### Other Swagger UI Parameters
+
+To see all the other possible configurations you can use, read the official docs for Swagger UI parameters.
+
+### JavaScript-only settings
+
+Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions).
+
+FastAPI also includes these JavaScript-only `presets` settings:
+
+```JavaScript
+presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+]
+```
+
+These are **JavaScript** objects, not strings, so you can't pass them from Python code directly.
+
+If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need.
diff --git a/docs/zh/docs/advanced/generate-clients.md b/docs/zh/docs/advanced/generate-clients.md
new file mode 100644
index 0000000000000..5edfccb23b1a5
--- /dev/null
+++ b/docs/zh/docs/advanced/generate-clients.md
@@ -0,0 +1,266 @@
+# Generate Clients
+
+As **FastAPI** is based on the OpenAPI specification, you get automatic compatibility with many tools, including the automatic API docs (provided by Swagger UI).
+
+One particular advantage that is not necessarily obvious is that you can **generate clients** (sometimes called **SDKs** ) for your API, for many different **programming languages**.
+
+## OpenAPI Client Generators
+
+There are many tools to generate clients from **OpenAPI**.
+
+A common tool is OpenAPI Generator.
+
+If you are building a **frontend**, a very interesting alternative is openapi-typescript-codegen.
+
+## Generate a TypeScript Frontend Client
+
+Let's start with a simple FastAPI application:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="7-9 12-13 16-17 21"
+ {!> ../../../docs_src/generate_clients/tutorial001_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-11 14-15 18 19 23"
+ {!> ../../../docs_src/generate_clients/tutorial001.py!}
+ ```
+
+Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`.
+
+### API Docs
+
+If you go to the API docs, you will see that it has the **schemas** for the data to be sent in requests and received in responses:
+
+
+
+You can see those schemas because they were declared with the models in the app.
+
+That information is available in the app's **OpenAPI schema**, and then shown in the API docs (by Swagger UI).
+
+And that same information from the models that is included in OpenAPI is what can be used to **generate the client code**.
+
+### Generate a TypeScript Client
+
+Now that we have the app with the models, we can generate the client code for the frontend.
+
+#### Install `openapi-typescript-codegen`
+
+You can install `openapi-typescript-codegen` in your frontend code with:
+
+
+
+You will also get autocompletion for the payload to send:
+
+
+
+!!! tip
+ Notice the autocompletion for `name` and `price`, that was defined in the FastAPI application, in the `Item` model.
+
+You will have inline errors for the data that you send:
+
+
+
+The response object will also have autocompletion:
+
+
+
+## FastAPI App with Tags
+
+In many cases your FastAPI app will be bigger, and you will probably use tags to separate different groups of *path operations*.
+
+For example, you could have a section for **items** and another section for **users**, and they could be separated by tags:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="21 26 34"
+ {!> ../../../docs_src/generate_clients/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="23 28 36"
+ {!> ../../../docs_src/generate_clients/tutorial002.py!}
+ ```
+
+### Generate a TypeScript Client with Tags
+
+If you generate a client for a FastAPI app using tags, it will normally also separate the client code based on the tags.
+
+This way you will be able to have things ordered and grouped correctly for the client code:
+
+
+
+In this case you have:
+
+* `ItemsService`
+* `UsersService`
+
+### Client Method Names
+
+Right now the generated method names like `createItemItemsPost` don't look very clean:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+...that's because the client generator uses the OpenAPI internal **operation ID** for each *path operation*.
+
+OpenAPI requires that each operation ID is unique across all the *path operations*, so FastAPI uses the **function name**, the **path**, and the **HTTP method/operation** to generate that operation ID, because that way it can make sure that the operation IDs are unique.
+
+But I'll show you how to improve that next. 🤓
+
+## Custom Operation IDs and Better Method Names
+
+You can **modify** the way these operation IDs are **generated** to make them simpler and have **simpler method names** in the clients.
+
+In this case you will have to ensure that each operation ID is **unique** in some other way.
+
+For example, you could make sure that each *path operation* has a tag, and then generate the operation ID based on the **tag** and the *path operation* **name** (the function name).
+
+### Custom Generate Unique ID Function
+
+FastAPI uses a **unique ID** for each *path operation*, it is used for the **operation ID** and also for the names of any needed custom models, for requests or responses.
+
+You can customize that function. It takes an `APIRoute` and outputs a string.
+
+For example, here it is using the first tag (you will probably have only one tag) and the *path operation* name (the function name).
+
+You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="6-7 10"
+ {!> ../../../docs_src/generate_clients/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8-9 12"
+ {!> ../../../docs_src/generate_clients/tutorial003.py!}
+ ```
+
+### Generate a TypeScript Client with Custom Operation IDs
+
+Now if you generate the client again, you will see that it has the improved method names:
+
+
+
+As you see, the method names now have the tag and then the function name, now they don't include information from the URL path and the HTTP operation.
+
+### Preprocess the OpenAPI Specification for the Client Generator
+
+The generated code still has some **duplicated information**.
+
+We already know that this method is related to the **items** because that word is in the `ItemsService` (taken from the tag), but we still have the tag name prefixed in the method name too. 😕
+
+We will probably still want to keep it for OpenAPI in general, as that will ensure that the operation IDs are **unique**.
+
+But for the generated client we could **modify** the OpenAPI operation IDs right before generating the clients, just to make those method names nicer and **cleaner**.
+
+We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this:
+
+```Python
+{!../../../docs_src/generate_clients/tutorial004.py!}
+```
+
+With that, the operation IDs would be renamed from things like `items-get_items` to just `get_items`, that way the client generator can generate simpler method names.
+
+### Generate a TypeScript Client with the Preprocessed OpenAPI
+
+Now as the end result is in a file `openapi.json`, you would modify the `package.json` to use that local file, for example:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "openapi-typescript-codegen": "^0.20.1",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+After generating the new client, you would now have **clean method names**, with all the **autocompletion**, **inline errors**, etc:
+
+
+
+## Benefits
+
+When using the automatically generated clients you would **autocompletion** for:
+
+* Methods.
+* Request payloads in the body, query parameters, etc.
+* Response payloads.
+
+You would also have **inline errors** for everything.
+
+And whenever you update the backend code, and **regenerate** the frontend, it would have any new *path operations* available as methods, the old ones removed, and any other change would be reflected on the generated code. 🤓
+
+This also means that if something changed it will be **reflected** on the client code automatically. And if you **build** the client it will error out if you have any **mismatch** in the data used.
+
+So, you would **detect many errors** very early in the development cycle instead of having to wait for the errors to show up to your final users in production and then trying to debug where the problem is. ✨
diff --git a/docs/zh/docs/advanced/graphql.md b/docs/zh/docs/advanced/graphql.md
new file mode 100644
index 0000000000000..1d2753fc4ce1b
--- /dev/null
+++ b/docs/zh/docs/advanced/graphql.md
@@ -0,0 +1,59 @@
+# GraphQL
+
+As **FastAPI** is based on the **ASGI** standard, it's very easy to integrate any **GraphQL** library also compatible with ASGI.
+
+You can combine normal FastAPI *path operations* with GraphQL on the same application.
+
+!!! tip
+ **GraphQL** solves some very specific use cases.
+
+ It has **advantages** and **disadvantages** when compared to common **web APIs**.
+
+ Make sure you evaluate if the **benefits** for your use case compensate the **drawbacks**. 🤓
+
+## GraphQL Libraries
+
+Here are some of the **GraphQL** libraries that have **ASGI** support. You could use them with **FastAPI**:
+
+* Strawberry 🍓
+ * With docs for FastAPI
+* Ariadne
+
+ * With docs for Starlette (that also apply to FastAPI)
+* Tartiflette
+
+ * With Tartiflette ASGI to provide ASGI integration
+* Graphene
+
+ * With starlette-graphene3
+
+## GraphQL with Strawberry
+
+If you need or want to work with **GraphQL**, **Strawberry** is the **recommended** library as it has the design closest to **FastAPI's** design, it's all based on **type annotations**.
+
+Depending on your use case, you might prefer to use a different library, but if you asked me, I would probably suggest you try **Strawberry**.
+
+Here's a small preview of how you could integrate Strawberry with FastAPI:
+
+```Python hl_lines="3 22 25-26"
+{!../../../docs_src/graphql/tutorial001.py!}
+```
+
+You can learn more about Strawberry in the Strawberry documentation.
+
+And also the docs about Strawberry with FastAPI.
+
+## Older `GraphQLApp` from Starlette
+
+Previous versions of Starlette included a `GraphQLApp` class to integrate with Graphene.
+
+It was deprecated from Starlette, but if you have code that used it, you can easily **migrate** to starlette-graphene3, that covers the same use case and has an **almost identical interface**.
+
+!!! tip
+ If you need GraphQL, I still would recommend you check out Strawberry, as it's based on type annotations instead of custom classes and types.
+
+## Learn More
+
+You can learn more about **GraphQL** in the official GraphQL documentation.
+
+You can also read more about each those libraries described above in their links.
diff --git a/docs/zh/docs/advanced/index.md b/docs/zh/docs/advanced/index.md
index 824f91f47ba90..c042c1d32422c 100644
--- a/docs/zh/docs/advanced/index.md
+++ b/docs/zh/docs/advanced/index.md
@@ -6,7 +6,7 @@
你会在接下来的章节中了解到其他的选项、配置以及额外的特性。
-!!! tip
+!!! !!! tip
接下来的章节**并不一定是**「高级的」。
而且对于你的使用场景来说,解决方案很可能就在其中。
@@ -16,3 +16,9 @@
你可能仍会用到 **FastAPI** 主教程 [教程 - 用户指南](../tutorial/){.internal-link target=_blank} 中的大多数特性。
接下来的章节我们认为你已经读过 [教程 - 用户指南](../tutorial/){.internal-link target=_blank},并且假设你已经知晓其中主要思想。
+
+## TestDriven.io course
+
+If you would like to take an advanced-beginner course to complement this section of the docs, you might want to check: Test-Driven Development with FastAPI and Docker by **TestDriven.io**.
+
+They are currently donating 10% of all profits to the development of **FastAPI**. 🎉 😄
diff --git a/docs/zh/docs/advanced/middleware.md b/docs/zh/docs/advanced/middleware.md
new file mode 100644
index 0000000000000..9219f1d2cb35d
--- /dev/null
+++ b/docs/zh/docs/advanced/middleware.md
@@ -0,0 +1,99 @@
+# Advanced Middleware
+
+In the main tutorial you read how to add [Custom Middleware](../tutorial/middleware.md){.internal-link target=_blank} to your application.
+
+And then you also read how to handle [CORS with the `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
+
+In this section we'll see how to use other middlewares.
+
+## Adding ASGI middlewares
+
+As **FastAPI** is based on Starlette and implements the ASGI specification, you can use any ASGI middleware.
+
+A middleware doesn't have to be made for FastAPI or Starlette to work, as long as it follows the ASGI spec.
+
+In general, ASGI middlewares are classes that expect to receive an ASGI app as the first argument.
+
+So, in the documentation for third-party ASGI middlewares they will probably tell you to do something like:
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+But FastAPI (actually Starlette) provides a simpler way to do it that makes sure that the internal middlewares to handle server errors and custom exception handlers work properly.
+
+For that, you use `app.add_middleware()` (as in the example for CORS).
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()` receives a middleware class as the first argument and any additional arguments to be passed to the middleware.
+
+## Integrated middlewares
+
+**FastAPI** includes several middlewares for common use cases, we'll see next how to use them.
+
+!!! note "Technical Details"
+ For the next examples, you could also use `from starlette.middleware.something import SomethingMiddleware`.
+
+ **FastAPI** provides several middlewares in `fastapi.middleware` just as a convenience for you, the developer. But most of the available middlewares come directly from Starlette.
+
+## `HTTPSRedirectMiddleware`
+
+Enforces that all incoming requests must either be `https` or `wss`.
+
+Any incoming requests to `http` or `ws` will be redirected to the secure scheme instead.
+
+```Python hl_lines="2 6"
+{!../../../docs_src/advanced_middleware/tutorial001.py!}
+```
+
+## `TrustedHostMiddleware`
+
+Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
+
+```Python hl_lines="2 6-8"
+{!../../../docs_src/advanced_middleware/tutorial002.py!}
+```
+
+The following arguments are supported:
+
+* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains. To allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
+
+If an incoming request does not validate correctly then a `400` response will be sent.
+
+## `GZipMiddleware`
+
+Handles GZip responses for any request that includes `"gzip"` in the `Accept-Encoding` header.
+
+The middleware will handle both standard and streaming responses.
+
+```Python hl_lines="2 6"
+{!../../../docs_src/advanced_middleware/tutorial003.py!}
+```
+
+The following arguments are supported:
+
+* `minimum_size` - Do not GZip responses that are smaller than this minimum size in bytes. Defaults to `500`.
+
+## Other middlewares
+
+There are many other ASGI middlewares.
+
+For example:
+
+* Sentry
+* Uvicorn's `ProxyHeadersMiddleware`
+* MessagePack
+
+To see other available middlewares check Starlette's Middleware docs and the ASGI Awesome List.
diff --git a/docs/zh/docs/advanced/nosql-databases.md b/docs/zh/docs/advanced/nosql-databases.md
new file mode 100644
index 0000000000000..f97f986c4261e
--- /dev/null
+++ b/docs/zh/docs/advanced/nosql-databases.md
@@ -0,0 +1,163 @@
+# NoSQL (Distributed / Big Data) Databases
+
+!!! info
+ These docs are about to be updated. 🎉
+
+ The current version assumes Pydantic v1.
+
+ The new docs will hopefully use Pydantic v2 and will use ODMantic with MongoDB.
+
+**FastAPI** can also be integrated with any NoSQL.
+
+Here we'll see an example using **Couchbase**, a document based NoSQL database.
+
+You can adapt it to any other NoSQL database like:
+
+* **MongoDB**
+* **Cassandra**
+* **CouchDB**
+* **ArangoDB**
+* **ElasticSearch**, etc.
+
+!!! tip
+ There is an official project generator with **FastAPI** and **Couchbase**, all based on **Docker**, including a frontend and more tools: https://github.com/tiangolo/full-stack-fastapi-couchbase
+
+## Import Couchbase components
+
+For now, don't pay attention to the rest, only the imports:
+
+```Python hl_lines="3-5"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+## Define a constant to use as a "document type"
+
+We will use it later as a fixed field `type` in our documents.
+
+This is not required by Couchbase, but is a good practice that will help you afterwards.
+
+```Python hl_lines="9"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+## Add a function to get a `Bucket`
+
+In **Couchbase**, a bucket is a set of documents, that can be of different types.
+
+They are generally all related to the same application.
+
+The analogy in the relational database world would be a "database" (a specific database, not the database server).
+
+The analogy in **MongoDB** would be a "collection".
+
+In the code, a `Bucket` represents the main entrypoint of communication with the database.
+
+This utility function will:
+
+* Connect to a **Couchbase** cluster (that might be a single machine).
+ * Set defaults for timeouts.
+* Authenticate in the cluster.
+* Get a `Bucket` instance.
+ * Set defaults for timeouts.
+* Return it.
+
+```Python hl_lines="12-21"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+## Create Pydantic models
+
+As **Couchbase** "documents" are actually just "JSON objects", we can model them with Pydantic.
+
+### `User` model
+
+First, let's create a `User` model:
+
+```Python hl_lines="24-28"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+We will use this model in our *path operation function*, so, we don't include in it the `hashed_password`.
+
+### `UserInDB` model
+
+Now, let's create a `UserInDB` model.
+
+This will have the data that is actually stored in the database.
+
+We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
+
+```Python hl_lines="31-33"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+!!! note
+ Notice that we have a `hashed_password` and a `type` field that will be stored in the database.
+
+ But it is not part of the general `User` model (the one we will return in the *path operation*).
+
+## Get the user
+
+Now create a function that will:
+
+* Take a username.
+* Generate a document ID from it.
+* Get the document with that ID.
+* Put the contents of the document in a `UserInDB` model.
+
+By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your *path operation function*, you can more easily re-use it in multiple parts and also add unit tests for it:
+
+```Python hl_lines="36-42"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+### f-strings
+
+If you are not familiar with the `f"userprofile::{username}"`, it is a Python "f-string".
+
+Any variable that is put inside of `{}` in an f-string will be expanded / injected in the string.
+
+### `dict` unpacking
+
+If you are not familiar with the `UserInDB(**result.value)`, it is using `dict` "unpacking".
+
+It will take the `dict` at `result.value`, and take each of its keys and values and pass them as key-values to `UserInDB` as keyword arguments.
+
+So, if the `dict` contains:
+
+```Python
+{
+ "username": "johndoe",
+ "hashed_password": "some_hash",
+}
+```
+
+It will be passed to `UserInDB` as:
+
+```Python
+UserInDB(username="johndoe", hashed_password="some_hash")
+```
+
+## Create your **FastAPI** code
+
+### Create the `FastAPI` app
+
+```Python hl_lines="46"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+### Create the *path operation function*
+
+As our code is calling Couchbase and we are not using the experimental Python await support, we should declare our function with normal `def` instead of `async def`.
+
+Also, Couchbase recommends not using a single `Bucket` object in multiple "threads", so, we can just get the bucket directly and pass it to our utility functions:
+
+```Python hl_lines="49-53"
+{!../../../docs_src/nosql_databases/tutorial001.py!}
+```
+
+## Recap
+
+You can integrate any third party NoSQL database, just using their standard packages.
+
+The same applies to any other external tool, system or API.
diff --git a/docs/zh/docs/advanced/openapi-callbacks.md b/docs/zh/docs/advanced/openapi-callbacks.md
new file mode 100644
index 0000000000000..14004d948e430
--- /dev/null
+++ b/docs/zh/docs/advanced/openapi-callbacks.md
@@ -0,0 +1,179 @@
+# OpenAPI Callbacks
+
+You could create an API with a *path operation* that could trigger a request to an *external API* created by someone else (probably the same developer that would be *using* your API).
+
+The process that happens when your API app calls the *external API* is named a "callback". Because the software that the external developer wrote sends a request to your API and then your API *calls back*, sending a request to an *external API* (that was probably created by the same developer).
+
+In this case, you could want to document how that external API *should* look like. What *path operation* it should have, what body it should expect, what response it should return, etc.
+
+## An app with callbacks
+
+Let's see all this with an example.
+
+Imagine you develop an app that allows creating invoices.
+
+These invoices will have an `id`, `title` (optional), `customer`, and `total`.
+
+The user of your API (an external developer) will create an invoice in your API with a POST request.
+
+Then your API will (let's imagine):
+
+* Send the invoice to some customer of the external developer.
+* Collect the money.
+* Send a notification back to the API user (the external developer).
+ * This will be done by sending a POST request (from *your API*) to some *external API* provided by that external developer (this is the "callback").
+
+## The normal **FastAPI** app
+
+Let's first see how the normal API app would look like before adding the callback.
+
+It will have a *path operation* that will receive an `Invoice` body, and a query parameter `callback_url` that will contain the URL for the callback.
+
+This part is pretty normal, most of the code is probably already familiar to you:
+
+```Python hl_lines="9-13 36-53"
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
+```
+
+!!! tip
+ The `callback_url` query parameter uses a Pydantic URL type.
+
+The only new thing is the `callbacks=messages_callback_router.routes` as an argument to the *path operation decorator*. We'll see what that is next.
+
+## Documenting the callback
+
+The actual callback code will depend heavily on your own API app.
+
+And it will probably vary a lot from one app to the next.
+
+It could be just one or two lines of code, like:
+
+```Python
+callback_url = "https://example.com/api/v1/invoices/events/"
+httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
+```
+
+But possibly the most important part of the callback is making sure that your API user (the external developer) implements the *external API* correctly, according to the data that *your API* is going to send in the request body of the callback, etc.
+
+So, what we will do next is add the code to document how that *external API* should look like to receive the callback from *your API*.
+
+That documentation will show up in the Swagger UI at `/docs` in your API, and it will let external developers know how to build the *external API*.
+
+This example doesn't implement the callback itself (that could be just a line of code), only the documentation part.
+
+!!! tip
+ The actual callback is just an HTTP request.
+
+ When implementing the callback yourself, you could use something like HTTPX or Requests.
+
+## Write the callback documentation code
+
+This code won't be executed in your app, we only need it to *document* how that *external API* should look like.
+
+But, you already know how to easily create automatic documentation for an API with **FastAPI**.
+
+So we are going to use that same knowledge to document how the *external API* should look like... by creating the *path operation(s)* that the external API should implement (the ones your API will call).
+
+!!! tip
+ When writing the code to document a callback, it might be useful to imagine that you are that *external developer*. And that you are currently implementing the *external API*, not *your API*.
+
+ Temporarily adopting this point of view (of the *external developer*) can help you feel like it's more obvious where to put the parameters, the Pydantic model for the body, for the response, etc. for that *external API*.
+
+### Create a callback `APIRouter`
+
+First create a new `APIRouter` that will contain one or more callbacks.
+
+```Python hl_lines="3 25"
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
+```
+
+### Create the callback *path operation*
+
+To create the callback *path operation* use the same `APIRouter` you created above.
+
+It should look just like a normal FastAPI *path operation*:
+
+* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.
+* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.
+
+```Python hl_lines="16-18 21-22 28-32"
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
+```
+
+There are 2 main differences from a normal *path operation*:
+
+* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`.
+* The *path* can contain an OpenAPI 3 expression (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
+
+### The callback path expression
+
+The callback *path* can have an OpenAPI 3 expression that can contain parts of the original request sent to *your API*.
+
+In this case, it's the `str`:
+
+```Python
+"{$callback_url}/invoices/{$request.body.id}"
+```
+
+So, if your API user (the external developer) sends a request to *your API* to:
+
+```
+https://yourapi.com/invoices/?callback_url=https://www.external.org/events
+```
+
+with a JSON body of:
+
+```JSON
+{
+ "id": "2expen51ve",
+ "customer": "Mr. Richie Rich",
+ "total": "9999"
+}
+```
+
+Then *your API* will process the invoice, and at some point later, send a callback request to the `callback_url` (the *external API*):
+
+```
+https://www.external.org/events/invoices/2expen51ve
+```
+
+with a JSON body containing something like:
+
+```JSON
+{
+ "description": "Payment celebration",
+ "paid": true
+}
+```
+
+and it would expect a response from that *external API* with a JSON body like:
+
+```JSON
+{
+ "ok": true
+}
+```
+
+!!! tip
+ Notice how the callback URL used contains the URL received as a query parameter in `callback_url` (`https://www.external.org/events`) and also the invoice `id` from inside of the JSON body (`2expen51ve`).
+
+### Add the callback router
+
+At this point you have the *callback path operation(s)* needed (the one(s) that the *external developer* should implement in the *external API*) in the callback router you created above.
+
+Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router:
+
+```Python hl_lines="35"
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
+```
+
+!!! tip
+ Notice that you are not passing the router itself (`invoices_callback_router`) to `callback=`, but the attribute `.routes`, as in `invoices_callback_router.routes`.
+
+### Check the docs
+
+Now you can start your app with Uvicorn and go to http://127.0.0.1:8000/docs.
+
+You will see your docs including a "Callback" section for your *path operation* that shows how the *external API* should look like:
+
+
diff --git a/docs/zh/docs/advanced/openapi-webhooks.md b/docs/zh/docs/advanced/openapi-webhooks.md
new file mode 100644
index 0000000000000..a41f8c820490d
--- /dev/null
+++ b/docs/zh/docs/advanced/openapi-webhooks.md
@@ -0,0 +1,51 @@
+# OpenAPI Webhooks
+
+There are cases where you want to tell your API **users** that your app could call *their* app (sending a request) with some data, normally to **notify** of some type of **event**.
+
+This means that instead of the normal process of your users sending requests to your API, it's **your API** (or your app) that could **send requests to their system** (to their API, their app).
+
+This is normally called a **webhook**.
+
+## Webhooks steps
+
+The process normally is that **you define** in your code what is the message that you will send, the **body of the request**.
+
+You also define in some way at which **moments** your app will send those requests or events.
+
+And **your users** define in some way (for example in a web dashboard somewhere) the **URL** where your app should send those requests.
+
+All the **logic** about how to register the URLs for webhooks and the code to actually send those requests is up to you. You write it however you want to in **your own code**.
+
+## Documenting webhooks with **FastAPI** and OpenAPI
+
+With **FastAPI**, using OpenAPI, you can define the names of these webhooks, the types of HTTP operations that your app can send (e.g. `POST`, `PUT`, etc.) and the request **bodies** that your app would send.
+
+This can make it a lot easier for your users to **implement their APIs** to receive your **webhook** requests, they might even be able to autogenerate some of their own API code.
+
+!!! info
+ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` and above.
+
+## An app with webhooks
+
+When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`.
+
+```Python hl_lines="9-13 36-53"
+{!../../../docs_src/openapi_webhooks/tutorial001.py!}
+```
+
+The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**.
+
+!!! info
+ The `app.webhooks` object is actually just an `APIRouter`, the same type you would use when structuring your app with multiple files.
+
+Notice that with webhooks you are actually not declaring a *path* (like `/items/`), the text you pass there is just an **identifier** of the webhook (the name of the event), for example in `@app.webhooks.post("new-subscription")`, the webhook name is `new-subscription`.
+
+This is because it is expected that **your users** would define the actual **URL path** where they want to receive the webhook request in some other way (e.g. a web dashboard).
+
+### Check the docs
+
+Now you can start your app with Uvicorn and go to http://127.0.0.1:8000/docs.
+
+You will see your docs have the normal *path operations* and now also some **webhooks**:
+
+
diff --git a/docs/zh/docs/advanced/path-operation-advanced-configuration.md b/docs/zh/docs/advanced/path-operation-advanced-configuration.md
index 7da9f251e30db..b9cbd79f35f9d 100644
--- a/docs/zh/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/zh/docs/advanced/path-operation-advanced-configuration.md
@@ -2,12 +2,12 @@
## OpenAPI 的 operationId
-!!! warning
+!!! !!! warning
如果你并非 OpenAPI 的「专家」,你可能不需要这部分内容。
你可以在路径操作中通过参数 `operation_id` 设置要使用的 OpenAPI `operationId`。
-务必确保每个操作路径的 `operation_id` 都是唯一的。
+You would have to make sure that it is unique for each operation.
```Python hl_lines="6"
{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!}
@@ -19,14 +19,14 @@
你应该在添加了所有 *路径操作* 之后执行此操作。
-```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
+```Python hl_lines="2 12-21 24"
{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
```
-!!! tip
+!!! !!! tip
如果你手动调用 `app.openapi()`,你应该在此之前更新 `operationId`。
-!!! warning
+!!! !!! warning
如果你这样做,务必确保你的每个 *路径操作函数* 的名字唯一。
即使它们在不同的模块中(Python 文件)。
@@ -47,7 +47,146 @@
剩余部分不会出现在文档中,但是其他工具(比如 Sphinx)可以使用剩余部分。
-
-```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
+```Python hl_lines="19-29"
{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
```
+
+## Additional Responses
+
+You probably have seen how to declare the `response_model` and `status_code` for a *path operation*.
+
+That defines the metadata about the main response of a *path operation*.
+
+You can also declare additional responses with their models, status codes, etc.
+
+There's a whole chapter here in the documentation about it, you can read it at [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}.
+
+## OpenAPI Extra
+
+When you declare a *path operation* in your application, **FastAPI** automatically generates the relevant metadata about that *path operation* to be included in the OpenAPI schema.
+
+!!! note "Technical details"
+ In the OpenAPI specification it is called the Operation Object.
+
+It has all the information about the *path operation* and is used to generate the automatic documentation.
+
+It includes the `tags`, `parameters`, `requestBody`, `responses`, etc.
+
+This *path operation*-specific OpenAPI schema is normally generated automatically by **FastAPI**, but you can also extend it.
+
+!!! tip
+ This is a low level extension point.
+
+ If you only need to declare additional responses, a more convenient way to do it is with [Additional Responses in OpenAPI](./additional-responses.md){.internal-link target=_blank}.
+
+You can extend the OpenAPI schema for a *path operation* using the parameter `openapi_extra`.
+
+### OpenAPI Extensions
+
+This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
+
+```Python hl_lines="6"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial005.py!}
+```
+
+If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*.
+
+
+
+And if you see the resulting OpenAPI (at `/openapi.json` in your API), you will see your extension as part of the specific *path operation* too:
+
+```JSON hl_lines="22"
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "x-aperture-labs-portal": "blue"
+ }
+ }
+ }
+}
+```
+
+### Custom OpenAPI *path operation* schema
+
+The dictionary in `openapi_extra` will be deeply merged with the automatically generated OpenAPI schema for the *path operation*.
+
+So, you could add additional data to the automatically generated schema.
+
+For example, you could decide to read and validate the request with your own code, without using the automatic features of FastAPI with Pydantic, but you could still want to define the request in the OpenAPI schema.
+
+You could do that with `openapi_extra`:
+
+```Python hl_lines="20-37 39-40"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial006.py!}
+```
+
+In this example, we didn't declare any Pydantic model. In fact, the request body is not even parsed as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.
+
+Nevertheless, we can declare the expected schema for the request body.
+
+### Custom OpenAPI content type
+
+Using this same trick, you could use a Pydantic model to define the JSON Schema that is then included in the custom OpenAPI schema section for the *path operation*.
+
+And you could do this even if the data type in the request is not JSON.
+
+For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON:
+
+=== "Pydantic v2"
+
+ ```Python hl_lines="17-22 24"
+ {!> ../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
+ ```
+
+=== "Pydantic v1"
+
+ ```Python hl_lines="17-22 24"
+ {!> ../../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py!}
+ ```
+
+!!! info
+ In Pydantic version 1 the method to get the JSON Schema for a model was called `Item.schema()`, in Pydantic version 2, the method is called `Item.model_schema_json()`.
+
+Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML.
+
+Then we use the request directly, and extract the body as `bytes`. This means that FastAPI won't even try to parse the request payload as JSON.
+
+And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content:
+
+=== "Pydantic v2"
+
+ ```Python hl_lines="26-33"
+ {!> ../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
+ ```
+
+=== "Pydantic v1"
+
+ ```Python hl_lines="26-33"
+ {!> ../../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py!}
+ ```
+
+!!! info
+ In Pydantic version 1 the method to parse and validate an object was `Item.parse_obj()`, in Pydantic version 2, the method is called `Item.model_validate()`.
+
+!!! tip
+ Here we re-use the same Pydantic model.
+
+ But the same way, we could have validated it in some other way.
diff --git a/docs/zh/docs/advanced/response-change-status-code.md b/docs/zh/docs/advanced/response-change-status-code.md
index a289cf20178f0..3bc41be37ad22 100644
--- a/docs/zh/docs/advanced/response-change-status-code.md
+++ b/docs/zh/docs/advanced/response-change-status-code.md
@@ -24,8 +24,10 @@
{!../../../docs_src/response_change_status_code/tutorial001.py!}
```
-然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
+然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。
+
+如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
**FastAPI**将使用这个临时响应来提取状态码(也包括cookies和头部),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。
-你也可以在依赖项中声明`Response`参数,并在其中设置状态码。但请注意,最后设置的状态码将会生效。
+你也可以在依赖项中声明`Response`参数,并在其中设置状态码。 但请注意,最后设置的状态码将会生效。
diff --git a/docs/zh/docs/advanced/response-cookies.md b/docs/zh/docs/advanced/response-cookies.md
index 3e53c53191a4c..810119ea8a6eb 100644
--- a/docs/zh/docs/advanced/response-cookies.md
+++ b/docs/zh/docs/advanced/response-cookies.md
@@ -4,6 +4,8 @@
你可以在 *路径函数* 中定义一个类型为 `Response`的参数,这样你就可以在这个临时响应对象中设置cookie了。
+And then you can set cookies in that *temporal* response object.
+
```Python hl_lines="1 8-9"
{!../../../docs_src/response_cookies/tutorial002.py!}
```
@@ -14,11 +16,11 @@
**FastAPI** 会使用这个 *临时* 响应对象去装在这些cookies信息 (同样还有headers和状态码等信息), 最终会将这些信息和通过`response_model`转化过的数据合并到最终的响应里。
-你也可以在depend中定义`Response`参数,并设置cookie和header。
+你还可以在直接响应`Response`时直接创建cookies。
## 直接响应 `Response`
-你还可以在直接响应`Response`时直接创建cookies。
+你也可以在depend中定义`Response`参数,并设置cookie和header。
你可以参考[Return a Response Directly](response-directly.md){.internal-link target=_blank}来创建response
@@ -28,20 +30,20 @@
{!../../../docs_src/response_cookies/tutorial001.py!}
```
-!!! tip
+!!! !!! tip
需要注意,如果你直接反馈一个response对象,而不是使用`Response`入参,FastAPI则会直接反馈你封装的response对象。
- 所以你需要确保你响应数据类型的正确性,如:你可以使用`JSONResponse`来兼容JSON的场景。
-
+ So, you will have to make sure your data is of the correct type. E.g. 所以你需要确保你响应数据类型的正确性,如:你可以使用`JSONResponse`来兼容JSON的场景。
+
同时,你也应当仅反馈通过`response_model`过滤过的数据。
### 更多信息
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以使用`from starlette.responses import Response` 或者 `from starlette.responses import JSONResponse`。
- 为了方便开发者,**FastAPI** 封装了相同数据类型,如`starlette.responses` 和 `fastapi.responses`。不过大部分response对象都是直接引用自Starlette。
-
+ 为了方便开发者,**FastAPI** 封装了相同数据类型,如`starlette.responses` 和 `fastapi.responses`。 不过大部分response对象都是直接引用自Starlette。
+
因为`Response`对象可以非常便捷的设置headers和cookies,所以 **FastAPI** 同时也封装了`fastapi.Response`。
如果你想查看所有可用的参数和选项,可以参考 Starlette帮助文档
diff --git a/docs/zh/docs/advanced/response-directly.md b/docs/zh/docs/advanced/response-directly.md
index 797a878eb923b..bd26889d9f64d 100644
--- a/docs/zh/docs/advanced/response-directly.md
+++ b/docs/zh/docs/advanced/response-directly.md
@@ -14,14 +14,14 @@
事实上,你可以返回任意 `Response` 或者任意 `Response` 的子类。
-!!! tip "小贴士"
+!!! !!! tip "小贴士"
`JSONResponse` 本身是一个 `Response` 的子类。
当你返回一个 `Response` 时,**FastAPI** 会直接传递它。
-**FastAPI** 不会用 Pydantic 模型做任何数据转换,不会将响应内容转换成任何类型,等等。
+It won't do any data conversion with Pydantic models, it won't convert the contents to any type, etc.
-这种特性给你极大的可扩展性。你可以返回任何数据类型,重写任何数据声明或者校验,等等。
+这种特性给你极大的可扩展性。 你可以返回任何数据类型,重写任何数据声明或者校验,等等。
## 在 `Response` 中使用 `jsonable_encoder`
@@ -31,19 +31,18 @@
对于这些情况,在将数据传递给响应之前,你可以使用 `jsonable_encoder` 来转换你的数据。
-
-```Python hl_lines="4 6 20 21"
+```Python hl_lines="6-7 21-22"
{!../../../docs_src/response_directly/tutorial001.py!}
```
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以使用 `from starlette.responses import JSONResponse`。
- 出于方便,**FastAPI** 会提供与 `starlette.responses` 相同的 `fastapi.responses` 给开发者。但是大多数可用的响应都直接来自 Starlette。
+ 出于方便,**FastAPI** 会提供与 `starlette.responses` 相同的 `fastapi.responses` 给开发者。 但是大多数可用的响应都直接来自 Starlette。
## 返回自定义 `Response`
-上面的例子展示了需要的所有部分,但还不够实用,因为你本可以只是直接返回 `item`,而**FastAPI** 默认帮你把这个 `item` 放到 `JSONResponse` 中,又默认将其转换成了 `dict`等等。
+上面的例子展示了需要的所有部分,但还不够实用,因为你本可以只是直接返回 `item`,而**FastAPI** 默认帮你把这个 `item` 放到 `JSONResponse` 中,又默认将其转换成了 `dict`等等。 All that by default.
现在,让我们看看你如何才能返回一个自定义的响应。
diff --git a/docs/zh/docs/advanced/response-headers.md b/docs/zh/docs/advanced/response-headers.md
index 85dab15ac092f..6ff939767b495 100644
--- a/docs/zh/docs/advanced/response-headers.md
+++ b/docs/zh/docs/advanced/response-headers.md
@@ -5,35 +5,38 @@
你可以在你的*路径操作函数*中声明一个`Response`类型的参数(就像你可以为cookies做的那样)。
然后你可以在这个*临时*响应对象中设置头部。
+
```Python hl_lines="1 7-8"
{!../../../docs_src/response_headers/tutorial002.py!}
```
-然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
+然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。
+
+如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
**FastAPI**将使用这个临时响应来提取头部(也包括cookies和状态码),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。
-你也可以在依赖项中声明`Response`参数,并在其中设置头部(和cookies)。
+你也可以在直接返回`Response`时添加头部。
## 直接返回 `Response`
-你也可以在直接返回`Response`时添加头部。
+You can also add headers when you return a `Response` directly.
按照[直接返回响应](response-directly.md){.internal-link target=_blank}中所述创建响应,并将头部作为附加参数传递:
+
```Python hl_lines="10-12"
{!../../../docs_src/response_headers/tutorial001.py!}
```
-
-!!! 注意 "技术细节"
+!!! !!! 注意 "技术细节"
你也可以使用`from starlette.responses import Response`或`from starlette.responses import JSONResponse`。
- **FastAPI**提供了与`fastapi.responses`相同的`starlette.responses`,只是为了方便开发者。但是,大多数可用的响应都直接来自Starlette。
-
+ **FastAPI**提供了与`fastapi.responses`相同的`starlette.responses`,只是为了方便开发者。 但是,大多数可用的响应都直接来自Starlette。
+
由于`Response`经常用于设置头部和cookies,因此**FastAPI**还在`fastapi.Response`中提供了它。
## 自定义头部
-请注意,可以使用'X-'前缀添加自定义专有头部。
+Have in mind that custom proprietary headers can be added using the 'X-' prefix.
但是,如果你有自定义头部,你希望浏览器中的客户端能够看到它们,你需要将它们添加到你的CORS配置中(在[CORS(跨源资源共享)](../tutorial/cors.md){.internal-link target=_blank}中阅读更多),使用在Starlette的CORS文档中记录的`expose_headers`参数。
diff --git a/docs/zh/docs/advanced/security/http-basic-auth.md b/docs/zh/docs/advanced/security/http-basic-auth.md
new file mode 100644
index 0000000000000..c24dfc8c7e25d
--- /dev/null
+++ b/docs/zh/docs/advanced/security/http-basic-auth.md
@@ -0,0 +1,164 @@
+# HTTP Basic Auth
+
+For the simplest cases, you can use HTTP Basic Auth.
+
+In HTTP Basic Auth, the application expects a header that contains a username and a password.
+
+If it doesn't receive it, it returns an HTTP 401 "Unauthorized" error.
+
+And returns a header `WWW-Authenticate` with a value of `Basic`, and an optional `realm` parameter.
+
+That tells the browser to show the integrated prompt for a username and password.
+
+Then, when you type that username and password, the browser sends them in the header automatically.
+
+## Simple HTTP Basic Auth
+
+* Import `HTTPBasic` and `HTTPBasicCredentials`.
+* Create a "`security` scheme" using `HTTPBasic`.
+* Use that `security` with a dependency in your *path operation*.
+* It returns an object of type `HTTPBasicCredentials`:
+ * It contains the `username` and `password` sent.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 8 12"
+ {!> ../../../docs_src/security/tutorial006_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="2 7 11"
+ {!> ../../../docs_src/security/tutorial006_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 6 10"
+ {!> ../../../docs_src/security/tutorial006.py!}
+ ```
+
+When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
+
+
+
+## Check the username
+
+Here's a more complete example.
+
+Use a dependency to check if the username and password are correct.
+
+For this, use the Python standard module `secrets` to check the username and password.
+
+`secrets.compare_digest()` needs to take `bytes` or a `str` that only contains ASCII characters (the ones in English), this means it wouldn't work with characters like `á`, as in `Sebastián`.
+
+To handle that, we first convert the `username` and `password` to `bytes` encoding them with UTF-8.
+
+Then we can use `secrets.compare_digest()` to ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 12-24"
+ {!> ../../../docs_src/security/tutorial007_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 12-24"
+ {!> ../../../docs_src/security/tutorial007_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1 11-21"
+ {!> ../../../docs_src/security/tutorial007.py!}
+ ```
+
+This would be similar to:
+
+```Python
+if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
+ # Return some error
+ ...
+```
+
+But by using the `secrets.compare_digest()` it will be secure against a type of attacks called "timing attacks".
+
+### Timing Attacks
+
+But what's a "timing attack"?
+
+Let's imagine some attackers are trying to guess the username and password.
+
+And they send a request with a username `johndoe` and a password `love123`.
+
+Then the Python code in your application would be equivalent to something like:
+
+```Python
+if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+But right at the moment Python compares the first `j` in `johndoe` to the first `s` in `stanleyjobson`, it will return `False`, because it already knows that those two strings are not the same, thinking that "there's no need to waste more computation comparing the rest of the letters". And your application will say "incorrect user or password".
+
+But then the attackers try with username `stanleyjobsox` and password `love123`.
+
+And your application code does something like:
+
+```Python
+if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Python will have to compare the whole `stanleyjobso` in both `stanleyjobsox` and `stanleyjobson` before realizing that both strings are not the same. So it will take some extra microseconds to reply back "incorrect user or password".
+
+#### The time to answer helps the attackers
+
+At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attackers will know that they got _something_ right, some of the initial letters were right.
+
+And then they can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
+
+#### A "professional" attack
+
+Of course, the attackers would not try all this by hand, they would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
+
+But doing that, in some minutes or hours the attackers would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
+
+#### Fix it with `secrets.compare_digest()`
+
+But in our code we are actually using `secrets.compare_digest()`.
+
+In short, it will take the same time to compare `stanleyjobsox` to `stanleyjobson` than it takes to compare `johndoe` to `stanleyjobson`. And the same for the password.
+
+That way, using `secrets.compare_digest()` in your application code, it will be safe against this whole range of security attacks.
+
+### Return the error
+
+After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="26-30"
+ {!> ../../../docs_src/security/tutorial007_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="26-30"
+ {!> ../../../docs_src/security/tutorial007_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="23-27"
+ {!> ../../../docs_src/security/tutorial007.py!}
+ ```
diff --git a/docs/zh/docs/advanced/security/index.md b/docs/zh/docs/advanced/security/index.md
index fdc8075c765ba..4cae9655474f7 100644
--- a/docs/zh/docs/advanced/security/index.md
+++ b/docs/zh/docs/advanced/security/index.md
@@ -4,7 +4,7 @@
除 [教程 - 用户指南: 安全性](../../tutorial/security/){.internal-link target=_blank} 中涵盖的功能之外,还有一些额外的功能来处理安全性.
-!!! tip "小贴士"
+!!! !!! tip "小贴士"
接下来的章节 **并不一定是 "高级的"**.
而且对于你的使用场景来说,解决方案很可能就在其中。
diff --git a/docs/zh/docs/advanced/security/oauth2-scopes.md b/docs/zh/docs/advanced/security/oauth2-scopes.md
new file mode 100644
index 0000000000000..3f230e9e74627
--- /dev/null
+++ b/docs/zh/docs/advanced/security/oauth2-scopes.md
@@ -0,0 +1,598 @@
+# OAuth2 scopes
+
+You can use OAuth2 scopes directly with **FastAPI**, they are integrated to work seamlessly.
+
+This would allow you to have a more fine-grained permission system, following the OAuth2 standard, integrated into your OpenAPI application (and the API docs).
+
+OAuth2 with scopes is the mechanism used by many big authentication providers, like Facebook, Google, GitHub, Microsoft, Twitter, etc. They use it to provide specific permissions to users and applications.
+
+Every time you "log in with" Facebook, Google, GitHub, Microsoft, Twitter, that application is using OAuth2 with scopes.
+
+In this section you will see how to manage authentication and authorization with the same OAuth2 with scopes in your **FastAPI** application.
+
+!!! warning
+ This is a more or less advanced section. If you are just starting, you can skip it.
+
+ You don't necessarily need OAuth2 scopes, and you can handle authentication and authorization however you want.
+
+ But OAuth2 with scopes can be nicely integrated into your API (with OpenAPI) and your API docs.
+
+ Nevertheless, you still enforce those scopes, or any other security/authorization requirement, however you need, in your code.
+
+ In many cases, OAuth2 with scopes can be an overkill.
+
+ But if you know you need it, or you are curious, keep reading.
+
+## OAuth2 scopes and OpenAPI
+
+The OAuth2 specification defines "scopes" as a list of strings separated by spaces.
+
+The content of each of these strings can have any format, but should not contain spaces.
+
+These scopes represent "permissions".
+
+In OpenAPI (e.g. the API docs), you can define "security schemes".
+
+When one of these security schemes uses OAuth2, you can also declare and use scopes.
+
+Each "scope" is just a string (without spaces).
+
+They are normally used to declare specific security permissions, for example:
+
+* `users:read` or `users:write` are common examples.
+* `instagram_basic` is used by Facebook / Instagram.
+* `https://www.googleapis.com/auth/drive` is used by Google.
+
+!!! info
+ In OAuth2 a "scope" is just a string that declares a specific permission required.
+
+ It doesn't matter if it has other characters like `:` or if it is a URL.
+
+ Those details are implementation specific.
+
+ For OAuth2 they are just strings.
+
+## Global view
+
+First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="4 8 12 46 64 105 107-115 121-124 128-134 139 155"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 155"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="2 4 8 12 47 65 106 108-116 122-125 129-135 140 156"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3 7 11 45 63 104 106-114 120-123 127-133 138 152"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 4 8 12 46 64 105 107-115 121-124 128-134 139 153"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+Now let's review those changes step by step.
+
+## OAuth2 Security scheme
+
+The first change is that now we are declaring the OAuth2 security scheme with two available scopes, `me` and `items`.
+
+The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="62-65"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="62-65"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="63-66"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="61-64"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="62-65"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="62-65"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize.
+
+And you will be able to select which scopes you want to give access to: `me` and `items`.
+
+This is the same mechanism used when you give permissions while logging in with Facebook, Google, GitHub, etc:
+
+
+
+## JWT token with scopes
+
+Now, modify the token *path operation* to return the scopes requested.
+
+We are still using the same `OAuth2PasswordRequestForm`. It includes a property `scopes` with a `list` of `str`, with each scope it received in the request.
+
+And we return the scopes as part of the JWT token.
+
+!!! danger
+ For simplicity, here we are just adding the scopes received directly to the token.
+
+ But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="155"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="155"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="156"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="152"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="153"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="153"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+## Declare scopes in *path operations* and dependencies
+
+Now we declare that the *path operation* for `/users/me/items/` requires the scope `items`.
+
+For this, we import and use `Security` from `fastapi`.
+
+You can use `Security` to declare dependencies (just like `Depends`), but `Security` also receives a parameter `scopes` with a list of scopes (strings).
+
+In this case, we pass a dependency function `get_current_active_user` to `Security` (the same way we would do with `Depends`).
+
+But we also pass a `list` of scopes, in this case with just one scope: `items` (it could have more).
+
+And the dependency function `get_current_active_user` can also declare sub-dependencies, not only with `Depends` but also with `Security`. Declaring its own sub-dependency function (`get_current_user`), and more scope requirements.
+
+In this case, it requires the scope `me` (it could require more than one scope).
+
+!!! note
+ You don't necessarily need to add different scopes in different places.
+
+ We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="4 139 170"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 139 170"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4 140 171"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3 138 165"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 139 166"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 139 166"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+!!! info "Technical Details"
+ `Security` is actually a subclass of `Depends`, and it has just one extra parameter that we'll see later.
+
+ But by using `Security` instead of `Depends`, **FastAPI** will know that it can declare security scopes, use them internally, and document the API with OpenAPI.
+
+ But when you import `Query`, `Path`, `Depends`, `Security` and others from `fastapi`, those are actually functions that return special classes.
+
+## Use `SecurityScopes`
+
+Now update the dependency `get_current_user`.
+
+This is the one used by the dependencies above.
+
+Here's were we are using the same OAuth2 scheme we created before, declaring it as a dependency: `oauth2_scheme`.
+
+Because this dependency function doesn't have any scope requirements itself, we can use `Depends` with `oauth2_scheme`, we don't have to use `Security` when we don't need to specify security scopes.
+
+We also declare a special parameter of type `SecurityScopes`, imported from `fastapi.security`.
+
+This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="8 105"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="8 105"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8 106"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 104"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8 105"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8 105"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+## Use the `scopes`
+
+The parameter `security_scopes` will be of type `SecurityScopes`.
+
+It will have a property `scopes` with a list containing all the scopes required by itself and all the dependencies that use this as a sub-dependency. That means, all the "dependants"... this might sound confusing, it is explained again later below.
+
+The `security_scopes` object (of class `SecurityScopes`) also provides a `scope_str` attribute with a single string, containing those scopes separated by spaces (we are going to use it).
+
+We create an `HTTPException` that we can re-use (`raise`) later at several points.
+
+In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in the `WWW-Authenticate` header (this is part of the spec).
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="105 107-115"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="105 107-115"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="106 108-116"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="104 106-114"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="105 107-115"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="105 107-115"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+## Verify the `username` and data shape
+
+We verify that we get a `username`, and extract the scopes.
+
+And then we validate that data with the Pydantic model (catching the `ValidationError` exception), and if we get an error reading the JWT token or validating the data with Pydantic, we raise the `HTTPException` we created before.
+
+For that, we update the Pydantic model `TokenData` with a new property `scopes`.
+
+By validating the data with Pydantic we can make sure that we have, for example, exactly a `list` of `str` with the scopes and a `str` with the `username`.
+
+Instead of, for example, a `dict`, or something else, as it could break the application at some point later, making it a security risk.
+
+We also verify that we have a user with that username, and if not, we raise that same exception we created before.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="46 116-127"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="46 116-127"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="47 117-128"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="45 115-126"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="46 116-127"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="46 116-127"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+## Verify the `scopes`
+
+We now verify that all the scopes required, by this dependency and all the dependants (including *path operations*), are included in the scopes provided in the token received, otherwise raise an `HTTPException`.
+
+For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="128-134"
+ {!> ../../../docs_src/security/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="128-134"
+ {!> ../../../docs_src/security/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="129-135"
+ {!> ../../../docs_src/security/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="127-133"
+ {!> ../../../docs_src/security/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="128-134"
+ {!> ../../../docs_src/security/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="128-134"
+ {!> ../../../docs_src/security/tutorial005.py!}
+ ```
+
+## Dependency tree and scopes
+
+Let's review again this dependency tree and the scopes.
+
+As the `get_current_active_user` dependency has as a sub-dependency on `get_current_user`, the scope `"me"` declared at `get_current_active_user` will be included in the list of required scopes in the `security_scopes.scopes` passed to `get_current_user`.
+
+The *path operation* itself also declares a scope, `"items"`, so this will also be in the list of `security_scopes.scopes` passed to `get_current_user`.
+
+Here's how the hierarchy of dependencies and scopes looks like:
+
+* The *path operation* `read_own_items` has:
+ * Required scopes `["items"]` with the dependency:
+ * `get_current_active_user`:
+ * The dependency function `get_current_active_user` has:
+ * Required scopes `["me"]` with the dependency:
+ * `get_current_user`:
+ * The dependency function `get_current_user` has:
+ * No scopes required by itself.
+ * A dependency using `oauth2_scheme`.
+ * A `security_scopes` parameter of type `SecurityScopes`:
+ * This `security_scopes` parameter has a property `scopes` with a `list` containing all these scopes declared above, so:
+ * `security_scopes.scopes` will contain `["me", "items"]` for the *path operation* `read_own_items`.
+ * `security_scopes.scopes` will contain `["me"]` for the *path operation* `read_users_me`, because it is declared in the dependency `get_current_active_user`.
+ * `security_scopes.scopes` will contain `[]` (nothing) for the *path operation* `read_system_status`, because it didn't declare any `Security` with `scopes`, and its dependency, `get_current_user`, doesn't declare any `scope` either.
+
+!!! tip
+ The important and "magic" thing here is that `get_current_user` will have a different list of `scopes` to check for each *path operation*.
+
+ All depending on the `scopes` declared in each *path operation* and each dependency in the dependency tree for that specific *path operation*.
+
+## More details about `SecurityScopes`
+
+You can use `SecurityScopes` at any point, and in multiple places, it doesn't have to be at the "root" dependency.
+
+It will always have the security scopes declared in the current `Security` dependencies and all the dependants for **that specific** *path operation* and **that specific** dependency tree.
+
+Because the `SecurityScopes` will have all the scopes declared by dependants, you can use it to verify that a token has the required scopes in a central dependency function, and then declare different scope requirements in different *path operations*.
+
+They will be checked independently for each *path operation*.
+
+## Check it
+
+If you open the API docs, you can authenticate and specify which scopes you want to authorize.
+
+
+
+If you don't select any scope, you will be "authenticated", but when you try to access `/users/me/` or `/users/me/items/` you will get an error saying that you don't have enough permissions. You will still be able to access `/status/`.
+
+And if you select the scope `me` but not the scope `items`, you will be able to access `/users/me/` but not `/users/me/items/`.
+
+That's what would happen to a third party application that tried to access one of these *path operations* with a token provided by a user, depending on how many permissions the user gave the application.
+
+## About third party integrations
+
+In this example we are using the OAuth2 "password" flow.
+
+This is appropriate when we are logging in to our own application, probably with our own frontend.
+
+Because we can trust it to receive the `username` and `password`, as we control it.
+
+But if you are building an OAuth2 application that others would connect to (i.e., if you are building an authentication provider equivalent to Facebook, Google, GitHub, etc.) you should use one of the other flows.
+
+The most common is the implicit flow.
+
+The most secure is the code flow, but is more complex to implement as it requires more steps. As it is more complex, many providers end up suggesting the implicit flow.
+
+!!! note
+ It's common that each authentication provider names their flows in a different way, to make it part of their brand.
+
+ But in the end, they are implementing the same OAuth2 standard.
+
+**FastAPI** includes utilities for all these OAuth2 authentication flows in `fastapi.security.oauth2`.
+
+## `Security` in decorator `dependencies`
+
+The same way you can define a `list` of `Depends` in the decorator's `dependencies` parameter (as explained in [Dependencies in path operation decorators](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), you could also use `Security` with `scopes` there.
diff --git a/docs/zh/docs/advanced/settings.md b/docs/zh/docs/advanced/settings.md
index 597e99a7793c3..d37bf11e79479 100644
--- a/docs/zh/docs/advanced/settings.md
+++ b/docs/zh/docs/advanced/settings.md
@@ -2,13 +2,13 @@
在许多情况下,您的应用程序可能需要一些外部设置或配置,例如密钥、数据库凭据、电子邮件服务的凭据等等。
-这些设置中的大多数是可变的(可以更改的),比如数据库的 URL。而且许多设置可能是敏感的,比如密钥。
+这些设置中的大多数是可变的(可以更改的),比如数据库的 URL。 而且许多设置可能是敏感的,比如密钥。
因此,通常会将它们提供为由应用程序读取的环境变量。
## 环境变量
-!!! tip
+!!! !!! tip
如果您已经知道什么是"环境变量"以及如何使用它们,请随意跳到下面的下一节。
环境变量(也称为"env var")是一种存在于 Python 代码之外、存在于操作系统中的变量,可以被您的 Python 代码(或其他程序)读取。
@@ -29,6 +29,7 @@
Hello Wade Wilson
```
+
=== "Windows PowerShell"
@@ -45,6 +46,7 @@
Hello Wade Wilson
```
+
### 在 Python 中读取环境变量
@@ -61,7 +63,7 @@ print(f"Hello {name} from Python")
```
!!! tip
- `os.getenv()` 的第二个参数是要返回的默认值。
+ The second argument to `os.getenv()` is the default value to return.
如果没有提供默认值,默认为 `None`,此处我们提供了 `"World"` 作为要使用的默认值。
@@ -92,8 +94,6 @@ Hello Wade Wilson from Python
由于环境变量可以在代码之外设置,但可以由代码读取,并且不需要与其他文件一起存储(提交到 `git`),因此通常将它们用于配置或设置。
-
-
您还可以仅为特定程序调用创建一个环境变量,该环境变量仅对该程序可用,并且仅在其运行期间有效。
要做到这一点,在程序本身之前的同一行创建它:
@@ -116,7 +116,7 @@ Hello World from Python
-!!! tip
+!!! !!! tip
您可以在 Twelve-Factor App: Config 中阅读更多相关信息。
### 类型和验证
@@ -129,7 +129,35 @@ Hello World from Python
幸运的是,Pydantic 提供了一个很好的工具来处理来自环境变量的设置,即Pydantic: Settings management。
-### 创建 `Settings` 对象
+### Install `pydantic-settings`
+
+!!! tip
+ 要使其工作,您需要执行 `pip install python-dotenv`。
+
+@lru_cache()。
+ ```
+。
+
+
+!!! !!! tip
如果您需要一个快速的复制粘贴示例,请不要使用此示例,而应使用下面的最后一个示例。
然后,当您创建该 `Settings` 类的实例(在此示例中是 `settings` 对象)时,Pydantic 将以不区分大小写的方式读取环境变量,因此,大写的变量 `APP_NAME` 仍将为属性 `app_name` 读取。
-然后,它将转换和验证数据。因此,当您使用该 `settings` 对象时,您将获得您声明的类型的数据(例如 `items_per_user` 将为 `int` 类型)。
+然后,它将转换和验证数据。 因此,当您使用该 `settings` 对象时,您将获得您声明的类型的数据(例如 `items_per_user` 将为 `int` 类型)。
-### 使用 `settings`
+### 创建 `Settings` 对象
然后,您可以在应用程序中使用新的 `settings` 对象:
@@ -158,7 +201,7 @@ Hello World from Python
### 运行服务器
-接下来,您将运行服务器,并将配置作为环境变量传递。例如,您可以设置一个 `ADMIN_EMAIL` 和 `APP_NAME`,如下所示:
+接下来,您将运行服务器,并将配置作为环境变量传递。 例如,您可以设置一个 `ADMIN_EMAIL` 和 `APP_NAME`,如下所示:
__init__.py 的文件,就像您在Bigger Applications - Multiple Files{.internal-link target=_blank}中看到的那样。
+ ```
+ 的文件,就像您在[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}中看到的那样。
+
+
+ !!! !!! tip
+ Config 类仅用于 Pydantic 配置。 您可以在Pydantic Model Config中阅读更多相关信息。
+
+
+!!! info
+ In Pydantic version 1 the configuration was done in an internal class `Config`, in Pydantic version 2 it's done in an attribute `model_config`. This attribute takes a `dict`, and to get autocompletion and inline errors you can import and use `SettingsConfigDict` to define that `dict`.
+
+在这里,我们在 Pydantic 的 `Settings` 类中创建了一个名为 `Config` 的类,并将 `env_file` 设置为我们想要使用的 dotenv 文件的文件名。
### 使用 `lru_cache` 仅创建一次 `Settings`
@@ -337,7 +399,7 @@ def get_settings():
我们将为每个请求创建该对象,并且将在每个请求中读取 `.env` 文件。 ⚠️
-但是,由于我们在顶部使用了 `@lru_cache()` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
+But as we are using the `@lru_cache()` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️
=== "Python 3.9+"
@@ -353,7 +415,7 @@ def get_settings():
=== "Python 3.6+ 非注解版本"
- !!! tip
+ !!! !!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="1 10"
@@ -366,9 +428,10 @@ def get_settings():
`@lru_cache()` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
-因此,下面的函数将对每个参数组合执行一次。然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。
+因此,下面的函数将对每个参数组合执行一次。 然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。
例如,如果您有一个函数:
+
```Python
@lru_cache()
def say_hi(name: str, salutation: str = "Ms."):
@@ -416,15 +479,28 @@ participant execute as Execute function
code ->> function: say_hi(name="Camila")
function ->> code: 返回存储的结果
end
+ function ->> execute: execute function code
+ execute ->> code: return the result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> code: return stored result
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: return stored result
+ end
```
对于我们的依赖项 `get_settings()`,该函数甚至不接受任何参数,因此它始终返回相同的值。
-这样,它的行为几乎就像是一个全局变量。但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。
+这样,它的行为几乎就像是一个全局变量。 但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。
`@lru_cache()` 是 `functools` 的一部分,它是 Python 标准库的一部分,您可以在Python 文档中了解有关 `@lru_cache()` 的更多信息。
-## 小结
+## Recap
您可以使用 Pydantic 设置处理应用程序的设置或配置,利用 Pydantic 模型的所有功能。
diff --git a/docs/zh/docs/advanced/sql-databases-peewee.md b/docs/zh/docs/advanced/sql-databases-peewee.md
new file mode 100644
index 0000000000000..4243e96e3e948
--- /dev/null
+++ b/docs/zh/docs/advanced/sql-databases-peewee.md
@@ -0,0 +1,536 @@
+# SQL (Relational) Databases with Peewee
+
+!!! warning
+ If you are just starting, the tutorial [SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank} that uses SQLAlchemy should be enough.
+
+ Feel free to skip this.
+
+ Peewee is not recommended with FastAPI as it doesn't play well with anything async Python. There are several better alternatives.
+
+!!! info
+ These docs assume Pydantic v1.
+
+ Because Pewee doesn't play well with anything async and there are better alternatives, I won't update these docs for Pydantic v2, they are kept for now only for historical purposes.
+
+If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM.
+
+If you already have a code base that uses Peewee ORM, you can check here how to use it with **FastAPI**.
+
+!!! warning "Python 3.7+ required"
+ You will need Python 3.7 or above to safely use Peewee with FastAPI.
+
+## Peewee for async
+
+Peewee was not designed for async frameworks, or with them in mind.
+
+Peewee has some heavy assumptions about its defaults and about how it should be used.
+
+If you are developing an application with an older non-async framework, and can work with all its defaults, **it can be a great tool**.
+
+But if you need to change some of the defaults, support more than one predefined database, work with an async framework (like FastAPI), etc, you will need to add quite some complex extra code to override those defaults.
+
+Nevertheless, it's possible to do it, and here you'll see exactly what code you have to add to be able to use Peewee with FastAPI.
+
+!!! note "Technical Details"
+ You can read more about Peewee's stand about async in Python in the docs, an issue, a PR.
+
+## The same app
+
+We are going to create the same application as in the SQLAlchemy tutorial ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}).
+
+Most of the code is actually the same.
+
+So, we are going to focus only on the differences.
+
+## File structure
+
+Let's say you have a directory named `my_super_project` that contains a sub-directory called `sql_app` with a structure like this:
+
+```
+.
+└── sql_app
+ ├── __init__.py
+ ├── crud.py
+ ├── database.py
+ ├── main.py
+ └── schemas.py
+```
+
+This is almost the same structure as we had for the SQLAlchemy tutorial.
+
+Now let's see what each file/module does.
+
+## Create the Peewee parts
+
+Let's refer to the file `sql_app/database.py`.
+
+### The standard Peewee code
+
+Let's first check all the normal Peewee code, create a Peewee database:
+
+```Python hl_lines="3 5 22"
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
+```
+
+!!! tip
+ Have in mind that if you wanted to use a different database, like PostgreSQL, you couldn't just change the string. You would need to use a different Peewee database class.
+
+#### Note
+
+The argument:
+
+```Python
+check_same_thread=False
+```
+
+is equivalent to the one in the SQLAlchemy tutorial:
+
+```Python
+connect_args={"check_same_thread": False}
+```
+
+...it is needed only for `SQLite`.
+
+!!! info "Technical Details"
+
+ Exactly the same technical details as in [SQL (Relational) Databases](../tutorial/sql-databases.md#note){.internal-link target=_blank} apply.
+
+### Make Peewee async-compatible `PeeweeConnectionState`
+
+The main issue with Peewee and FastAPI is that Peewee relies heavily on Python's `threading.local`, and it doesn't have a direct way to override it or let you handle connections/sessions directly (as is done in the SQLAlchemy tutorial).
+
+And `threading.local` is not compatible with the new async features of modern Python.
+
+!!! note "Technical Details"
+ `threading.local` is used to have a "magic" variable that has a different value for each thread.
+
+ This was useful in older frameworks designed to have one single thread per request, no more, no less.
+
+ Using this, each request would have its own database connection/session, which is the actual final goal.
+
+ But FastAPI, using the new async features, could handle more than one request on the same thread. And at the same time, for a single request, it could run multiple things in different threads (in a threadpool), depending on if you use `async def` or normal `def`. This is what gives all the performance improvements to FastAPI.
+
+But Python 3.7 and above provide a more advanced alternative to `threading.local`, that can also be used in the places where `threading.local` would be used, but is compatible with the new async features.
+
+We are going to use that. It's called `contextvars`.
+
+We are going to override the internal parts of Peewee that use `threading.local` and replace them with `contextvars`, with the corresponding updates.
+
+This might seem a bit complex (and it actually is), you don't really need to completely understand how it works to use it.
+
+We will create a `PeeweeConnectionState`:
+
+```Python hl_lines="10-19"
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
+```
+
+This class inherits from a special internal class used by Peewee.
+
+It has all the logic to make Peewee use `contextvars` instead of `threading.local`.
+
+`contextvars` works a bit differently than `threading.local`. But the rest of Peewee's internal code assumes that this class works with `threading.local`.
+
+So, we need to do some extra tricks to make it work as if it was just using `threading.local`. The `__init__`, `__setattr__`, and `__getattr__` implement all the required tricks for this to be used by Peewee without knowing that it is now compatible with FastAPI.
+
+!!! tip
+ This will just make Peewee behave correctly when used with FastAPI. Not randomly opening or closing connections that are being used, creating errors, etc.
+
+ But it doesn't give Peewee async super-powers. You should still use normal `def` functions and not `async def`.
+
+### Use the custom `PeeweeConnectionState` class
+
+Now, overwrite the `._state` internal attribute in the Peewee database `db` object using the new `PeeweeConnectionState`:
+
+```Python hl_lines="24"
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
+```
+
+!!! tip
+ Make sure you overwrite `db._state` *after* creating `db`.
+
+!!! tip
+ You would do the same for any other Peewee database, including `PostgresqlDatabase`, `MySQLDatabase`, etc.
+
+## Create the database models
+
+Let's now see the file `sql_app/models.py`.
+
+### Create Peewee models for our data
+
+Now create the Peewee models (classes) for `User` and `Item`.
+
+This is the same you would do if you followed the Peewee tutorial and updated the models to have the same data as in the SQLAlchemy tutorial.
+
+!!! tip
+ Peewee also uses the term "**model**" to refer to these classes and instances that interact with the database.
+
+ But Pydantic also uses the term "**model**" to refer to something different, the data validation, conversion, and documentation classes and instances.
+
+Import `db` from `database` (the file `database.py` from above) and use it here.
+
+```Python hl_lines="3 6-12 15-21"
+{!../../../docs_src/sql_databases_peewee/sql_app/models.py!}
+```
+
+!!! tip
+ Peewee creates several magic attributes.
+
+ It will automatically add an `id` attribute as an integer to be the primary key.
+
+ It will chose the name of the tables based on the class names.
+
+ For the `Item`, it will create an attribute `owner_id` with the integer ID of the `User`. But we don't declare it anywhere.
+
+## Create the Pydantic models
+
+Now let's check the file `sql_app/schemas.py`.
+
+!!! tip
+ To avoid confusion between the Peewee *models* and the Pydantic *models*, we will have the file `models.py` with the Peewee models, and the file `schemas.py` with the Pydantic models.
+
+ These Pydantic models define more or less a "schema" (a valid data shape).
+
+ So this will help us avoiding confusion while using both.
+
+### Create the Pydantic *models* / schemas
+
+Create all the same Pydantic models as in the SQLAlchemy tutorial:
+
+```Python hl_lines="16-18 21-22 25-30 34-35 38-39 42-48"
+{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
+```
+
+!!! tip
+ Here we are creating the models with an `id`.
+
+ We didn't explicitly specify an `id` attribute in the Peewee models, but Peewee adds one automatically.
+
+ We are also adding the magic `owner_id` attribute to `Item`.
+
+### Create a `PeeweeGetterDict` for the Pydantic *models* / schemas
+
+When you access a relationship in a Peewee object, like in `some_user.items`, Peewee doesn't provide a `list` of `Item`.
+
+It provides a special custom object of class `ModelSelect`.
+
+It's possible to create a `list` of its items with `list(some_user.items)`.
+
+But the object itself is not a `list`. And it's also not an actual Python generator. Because of this, Pydantic doesn't know by default how to convert it to a `list` of Pydantic *models* / schemas.
+
+But recent versions of Pydantic allow providing a custom class that inherits from `pydantic.utils.GetterDict`, to provide the functionality used when using the `orm_mode = True` to retrieve the values for ORM model attributes.
+
+We are going to create a custom `PeeweeGetterDict` class and use it in all the same Pydantic *models* / schemas that use `orm_mode`:
+
+```Python hl_lines="3 8-13 31 49"
+{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
+```
+
+Here we are checking if the attribute that is being accessed (e.g. `.items` in `some_user.items`) is an instance of `peewee.ModelSelect`.
+
+And if that's the case, just return a `list` with it.
+
+And then we use it in the Pydantic *models* / schemas that use `orm_mode = True`, with the configuration variable `getter_dict = PeeweeGetterDict`.
+
+!!! tip
+ We only need to create one `PeeweeGetterDict` class, and we can use it in all the Pydantic *models* / schemas.
+
+## CRUD utils
+
+Now let's see the file `sql_app/crud.py`.
+
+### Create all the CRUD utils
+
+Create all the same CRUD utils as in the SQLAlchemy tutorial, all the code is very similar:
+
+```Python hl_lines="1 4-5 8-9 12-13 16-20 23-24 27-30"
+{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!}
+```
+
+There are some differences with the code for the SQLAlchemy tutorial.
+
+We don't pass a `db` attribute around. Instead we use the models directly. This is because the `db` object is a global object, that includes all the connection logic. That's why we had to do all the `contextvars` updates above.
+
+Aso, when returning several objects, like in `get_users`, we directly call `list`, like in:
+
+```Python
+list(models.User.select())
+```
+
+This is for the same reason that we had to create a custom `PeeweeGetterDict`. But by returning something that is already a `list` instead of the `peewee.ModelSelect` the `response_model` in the *path operation* with `List[models.User]` (that we'll see later) will work correctly.
+
+## Main **FastAPI** app
+
+And now in the file `sql_app/main.py` let's integrate and use all the other parts we created before.
+
+### Create the database tables
+
+In a very simplistic way create the database tables:
+
+```Python hl_lines="9-11"
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
+```
+
+### Create a dependency
+
+Create a dependency that will connect the database right at the beginning of a request and disconnect it at the end:
+
+```Python hl_lines="23-29"
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
+```
+
+Here we have an empty `yield` because we are actually not using the database object directly.
+
+It is connecting to the database and storing the connection data in an internal variable that is independent for each request (using the `contextvars` tricks from above).
+
+Because the database connection is potentially I/O blocking, this dependency is created with a normal `def` function.
+
+And then, in each *path operation function* that needs to access the database we add it as a dependency.
+
+But we are not using the value given by this dependency (it actually doesn't give any value, as it has an empty `yield`). So, we don't add it to the *path operation function* but to the *path operation decorator* in the `dependencies` parameter:
+
+```Python hl_lines="32 40 47 59 65 72"
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
+```
+
+### Context variable sub-dependency
+
+For all the `contextvars` parts to work, we need to make sure we have an independent value in the `ContextVar` for each request that uses the database, and that value will be used as the database state (connection, transactions, etc) for the whole request.
+
+For that, we need to create another `async` dependency `reset_db_state()` that is used as a sub-dependency in `get_db()`. It will set the value for the context variable (with just a default `dict`) that will be used as the database state for the whole request. And then the dependency `get_db()` will store in it the database state (connection, transactions, etc).
+
+```Python hl_lines="18-20"
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
+```
+
+For the **next request**, as we will reset that context variable again in the `async` dependency `reset_db_state()` and then create a new connection in the `get_db()` dependency, that new request will have its own database state (connection, transactions, etc).
+
+!!! tip
+ As FastAPI is an async framework, one request could start being processed, and before finishing, another request could be received and start processing as well, and it all could be processed in the same thread.
+
+ But context variables are aware of these async features, so, a Peewee database state set in the `async` dependency `reset_db_state()` will keep its own data throughout the entire request.
+
+ And at the same time, the other concurrent request will have its own database state that will be independent for the whole request.
+
+#### Peewee Proxy
+
+If you are using a Peewee Proxy, the actual database is at `db.obj`.
+
+So, you would reset it with:
+
+```Python hl_lines="3-4"
+async def reset_db_state():
+ database.db.obj._state._state.set(db_state_default.copy())
+ database.db.obj._state.reset()
+```
+
+### Create your **FastAPI** *path operations*
+
+Now, finally, here's the standard **FastAPI** *path operations* code.
+
+```Python hl_lines="32-37 40-43 46-53 56-62 65-68 71-79"
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
+```
+
+### About `def` vs `async def`
+
+The same as with SQLAlchemy, we are not doing something like:
+
+```Python
+user = await models.User.select().first()
+```
+
+...but instead we are using:
+
+```Python
+user = models.User.select().first()
+```
+
+So, again, we should declare the *path operation functions* and the dependency without `async def`, just with a normal `def`, as:
+
+```Python hl_lines="2"
+# Something goes here
+def read_users(skip: int = 0, limit: int = 100):
+ # Something goes here
+```
+
+## Testing Peewee with async
+
+This example includes an extra *path operation* that simulates a long processing request with `time.sleep(sleep_time)`.
+
+It will have the database connection open at the beginning and will just wait some seconds before replying back. And each new request will wait one second less.
+
+This will easily let you test that your app with Peewee and FastAPI is behaving correctly with all the stuff about threads.
+
+If you want to check how Peewee would break your app if used without modification, go the the `sql_app/database.py` file and comment the line:
+
+```Python
+# db._state = PeeweeConnectionState()
+```
+
+And in the file `sql_app/main.py` file, comment the body of the `async` dependency `reset_db_state()` and replace it with a `pass`:
+
+```Python
+async def reset_db_state():
+# database.db._state._state.set(db_state_default.copy())
+# database.db._state.reset()
+ pass
+```
+
+Then run your app with Uvicorn:
+
+
+
+And then, open the docs for the sub-application, at http://127.0.0.1:8000/subapi/docs.
+
+You will see the automatic API docs for the sub-application, including only its own _path operations_, all under the correct sub-path prefix `/subapi`:
+
+
+
+If you try interacting with any of the two user interfaces, they will work correctly, because the browser will be able to talk to each specific app or sub-app.
+
+### Technical Details: `root_path`
+
+When you mount a sub-application as described above, FastAPI will take care of communicating the mount path for the sub-application using a mechanism from the ASGI specification called a `root_path`.
+
+That way, the sub-application will know to use that path prefix for the docs UI.
+
+And the sub-application could also have its own mounted sub-applications and everything would work correctly, because FastAPI handles all these `root_path`s automatically.
+
+You will learn more about the `root_path` and how to use it explicitly in the section about [Behind a Proxy](./behind-a-proxy.md){.internal-link target=_blank}.
diff --git a/docs/zh/docs/advanced/templates.md b/docs/zh/docs/advanced/templates.md
new file mode 100644
index 0000000000000..38618aeeb09cd
--- /dev/null
+++ b/docs/zh/docs/advanced/templates.md
@@ -0,0 +1,77 @@
+# Templates
+
+You can use any template engine you want with **FastAPI**.
+
+A common choice is Jinja2, the same one used by Flask and other tools.
+
+There are utilities to configure it easily that you can use directly in your **FastAPI** application (provided by Starlette).
+
+## Install dependencies
+
+Install `jinja2`:
+
+
+
您可以在输入框中输入消息并发送:
-
+
您的 **FastAPI** 应用程序将回复:
-
+
您可以发送(和接收)多条消息:
-
+
所有这些消息都将使用同一个 WebSocket 连
-接。
-
## 使用 `Depends` 和其他依赖项
在 WebSocket 端点中,您可以从 `fastapi` 导入并使用以下内容:
@@ -124,25 +126,25 @@ $ uvicorn main:app --reload
{!> ../../../docs_src/websockets/tutorial002_an.py!}
```
-=== "Python 3.10+ 非带注解版本"
+=== "Python 3.6+ 非带注解版本"
- !!! tip
+ !!! !!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="66-67 79"
{!> ../../../docs_src/websockets/tutorial002_py310.py!}
```
-=== "Python 3.6+ 非带注解版本"
+=== "Python 3.10+ 非带注解版本"
- !!! tip
+ !!! !!! tip
如果可能,请尽量使用 `Annotated` 版本。
```Python hl_lines="68-69 81"
{!> ../../../docs_src/websockets/tutorial002.py!}
```
-!!! info
+!!! !!! info
由于这是一个 WebSocket,抛出 `HTTPException` 并不是很合理,而是抛出 `WebSocketException`。
您可以使用规范中定义的有效代码。
@@ -151,11 +153,13 @@ $ uvicorn main:app --reload
如果您的文件名为 `main.py`,请使用以下命令运行应用程序:
-```console
+
+
## 处理断开连接和多个客户端
@@ -190,7 +194,7 @@ $ uvicorn main:app --reload
尝试以下操作:
* 使用多个浏览器选项卡打开应用程序。
-* 从这些选项卡中发送消息。
+* Write messages from them.
* 然后关闭其中一个选项卡。
这将引发 `WebSocketDisconnect` 异常,并且所有其他客户端都会收到类似以下的消息:
@@ -199,16 +203,16 @@ $ uvicorn main:app --reload
Client #1596980209979 left the chat
```
-!!! tip
+!!! !!! tip
上面的应用程序是一个最小和简单的示例,用于演示如何处理和向多个 WebSocket 连接广播消息。
但请记住,由于所有内容都在内存中以单个列表的形式处理,因此它只能在进程运行时工作,并且只能使用单个进程。
-
+
如果您需要与 FastAPI 集成更简单但更强大的功能,支持 Redis、PostgreSQL 或其他功能,请查看 [encode/broadcaster](https://github.com/encode/broadcaster)。
## 更多信息
要了解更多选项,请查看 Starlette 的文档:
-* [WebSocket 类](https://www.starlette.io/websockets/)
+* WebSocket 类
* [基于类的 WebSocket 处理](https://www.starlette.io/endpoints/#websocketendpoint)。
diff --git a/docs/zh/docs/advanced/wsgi.md b/docs/zh/docs/advanced/wsgi.md
index ad71280fc6180..e39b8eb3d26c9 100644
--- a/docs/zh/docs/advanced/wsgi.md
+++ b/docs/zh/docs/advanced/wsgi.md
@@ -12,7 +12,7 @@
之后将其挂载到某一个路径下。
-```Python hl_lines="2-3 22"
+```Python hl_lines="2-3 23"
{!../../../docs_src/wsgi/tutorial001.py!}
```
diff --git a/docs/zh/docs/alternatives.md b/docs/zh/docs/alternatives.md
new file mode 100644
index 0000000000000..b9f184cccfe55
--- /dev/null
+++ b/docs/zh/docs/alternatives.md
@@ -0,0 +1,398 @@
+# Alternatives, Inspiration and Comparisons
+
+What inspired **FastAPI**, how it compares to other alternatives and what it learned from them.
+
+## Intro
+
+**FastAPI** wouldn't exist if not for the previous work of others.
+
+There have been many tools created before that have helped inspire its creation.
+
+I have been avoiding the creation of a new framework for several years. First I tried to solve all the features covered by **FastAPI** using many different frameworks, plug-ins, and tools.
+
+But at some point, there was no other option than creating something that provided all these features, taking the best ideas from previous tools, and combining them in the best way possible, using language features that weren't even available before (Python 3.6+ type hints).
+
+## Previous tools
+
+### Django
+
+It's the most popular Python framework and is widely trusted. It is used to build systems like Instagram.
+
+It's relatively tightly coupled with relational databases (like MySQL or PostgreSQL), so, having a NoSQL database (like Couchbase, MongoDB, Cassandra, etc) as the main store engine is not very easy.
+
+It was created to generate the HTML in the backend, not to create APIs used by a modern frontend (like React, Vue.js and Angular) or by other systems (like IoT devices) communicating with it.
+
+### Django REST Framework
+
+Django REST framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities.
+
+It is used by many companies including Mozilla, Red Hat and Eventbrite.
+
+It was one of the first examples of **automatic API documentation**, and this was specifically one of the first ideas that inspired "the search for" **FastAPI**.
+
+!!! note
+ Django REST Framework was created by Tom Christie. The same creator of Starlette and Uvicorn, on which **FastAPI** is based.
+
+
+!!! check "Inspired **FastAPI** to" Have an automatic API documentation web user interface.
+
+### Flask
+
+Flask is a "microframework", it doesn't include database integrations nor many of the things that come by default in Django.
+
+This simplicity and flexibility allow doing things like using NoSQL databases as the main data storage system.
+
+As it is very simple, it's relatively intuitive to learn, although the documentation gets somewhat technical at some points.
+
+It is also commonly used for other applications that don't necessarily need a database, user management, or any of the many features that come pre-built in Django. Although many of these features can be added with plug-ins.
+
+This decoupling of parts, and being a "microframework" that could be extended to cover exactly what is needed was a key feature that I wanted to keep.
+
+Given the simplicity of Flask, it seemed like a good match for building APIs. The next thing to find was a "Django REST Framework" for Flask.
+
+!!! check "Inspired **FastAPI** to" Be a micro-framework. Making it easy to mix and match the tools and parts needed.
+
+ Have a simple and easy to use routing system.
+
+
+### Requests
+
+**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.
+
+It would actually be common to use Requests *inside* of a FastAPI application.
+
+But still, FastAPI got quite some inspiration from Requests.
+
+**Requests** is a library to *interact* with APIs (as a client), while **FastAPI** is a library to *build* APIs (as a server).
+
+They are, more or less, at opposite ends, complementing each other.
+
+Requests has a very simple and intuitive design, it's very easy to use, with sensible defaults. But at the same time, it's very powerful and customizable.
+
+That's why, as said in the official website:
+
+> Requests is one of the most downloaded Python packages of all time
+
+The way you use it is very simple. For example, to do a `GET` request, you would write:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+The FastAPI counterpart API *path operation* could look like:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+See the similarities in `requests.get(...)` and `@app.get(...)`.
+
+!!! check "Inspired **FastAPI** to"
+ * Have a simple and intuitive API.
+ * Use HTTP method names (operations) directly, in a straightforward and intuitive way.
+ * Have sensible defaults, but powerful customizations.
+
+
+### Swagger / OpenAPI
+
+The main feature I wanted from Django REST Framework was the automatic API documentation.
+
+Then I found that there was a standard to document APIs, using JSON (or YAML, an extension of JSON) called Swagger.
+
+And there was a web user interface for Swagger APIs already created. So, being able to generate Swagger documentation for an API would allow using this web user interface automatically.
+
+At some point, Swagger was given to the Linux Foundation, to be renamed OpenAPI.
+
+That's why when talking about version 2.0 it's common to say "Swagger", and for version 3+ "OpenAPI".
+
+!!! check "Inspired **FastAPI** to" Adopt and use an open standard for API specifications, instead of a custom schema.
+
+ And integrate standards-based user interface tools:
+
+ * Swagger UI
+ * ReDoc
+
+ These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
+
+### Flask REST frameworks
+
+There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
+
+### Marshmallow
+
+One of the main features needed by API systems is data "serialization" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.
+
+Another big feature needed by APIs is data validation, making sure that the data is valid, given certain parameters. For example, that some field is an `int`, and not some random string. This is especially useful for incoming data.
+
+Without a data validation system, you would have to do all the checks by hand, in code.
+
+These features are what Marshmallow was built to provide. It is a great library, and I have used it a lot before.
+
+But it was created before there existed Python type hints. So, to define every schema you need to use specific utils and classes provided by Marshmallow.
+
+!!! check "Inspired **FastAPI** to" Use code to define "schemas" that provide data types and validation, automatically.
+
+### Webargs
+
+Another big feature required by APIs is parsing data from incoming requests.
+
+Webargs is a tool that was made to provide that on top of several frameworks, including Flask.
+
+It uses Marshmallow underneath to do the data validation. And it was created by the same developers.
+
+It's a great tool and I have used it a lot too, before having **FastAPI**.
+
+!!! info
+ Webargs was created by the same Marshmallow developers.
+
+!!! check "Inspired **FastAPI** to" Have automatic validation of incoming request data.
+
+### APISpec
+
+Marshmallow and Webargs provide validation, parsing and serialization as plug-ins.
+
+But documentation is still missing. Then APISpec was created.
+
+It is a plug-in for many frameworks (and there's a plug-in for Starlette too).
+
+The way it works is that you write the definition of the schema using YAML format inside the docstring of each function handling a route.
+
+And it generates OpenAPI schemas.
+
+That's how it works in Flask, Starlette, Responder, etc.
+
+But then, we have again the problem of having a micro-syntax, inside of a Python string (a big YAML).
+
+The editor can't help much with that. And if we modify parameters or Marshmallow schemas and forget to also modify that YAML docstring, the generated schema would be obsolete.
+
+!!! info
+ APISpec was created by the same Marshmallow developers.
+
+
+!!! check "Inspired **FastAPI** to" Support the open standard for APIs, OpenAPI.
+
+### Flask-apispec
+
+It's a Flask plug-in, that ties together Webargs, Marshmallow and APISpec.
+
+It uses the information from Webargs and Marshmallow to automatically generate OpenAPI schemas, using APISpec.
+
+It's a great tool, very under-rated. It should be way more popular than many Flask plug-ins out there. It might be due to its documentation being too concise and abstract.
+
+This solved having to write YAML (another syntax) inside of Python docstrings.
+
+This combination of Flask, Flask-apispec with Marshmallow and Webargs was my favorite backend stack until building **FastAPI**.
+
+Using it led to the creation of several Flask full-stack generators. These are the main stack I (and several external teams) have been using up to now:
+
+* https://github.com/tiangolo/full-stack
+* https://github.com/tiangolo/full-stack-flask-couchbase
+* https://github.com/tiangolo/full-stack-flask-couchdb
+
+And these same full-stack generators were the base of the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}.
+
+!!! info
+ Flask-apispec was created by the same Marshmallow developers.
+
+!!! check "Inspired **FastAPI** to" Generate the OpenAPI schema automatically, from the same code that defines serialization and validation.
+
+### NestJS (and Angular)
+
+This isn't even Python, NestJS is a JavaScript (TypeScript) NodeJS framework inspired by Angular.
+
+It achieves something somewhat similar to what can be done with Flask-apispec.
+
+It has an integrated dependency injection system, inspired by Angular two. It requires pre-registering the "injectables" (like all the other dependency injection systems I know), so, it adds to the verbosity and code repetition.
+
+As the parameters are described with TypeScript types (similar to Python type hints), editor support is quite good.
+
+But as TypeScript data is not preserved after compilation to JavaScript, it cannot rely on the types to define validation, serialization and documentation at the same time. Due to this and some design decisions, to get validation, serialization and automatic schema generation, it's needed to add decorators in many places. So, it becomes quite verbose.
+
+It can't handle nested models very well. So, if the JSON body in the request is a JSON object that has inner fields that in turn are nested JSON objects, it cannot be properly documented and validated.
+
+!!! check "Inspired **FastAPI** to" Use Python types to have great editor support.
+
+ Have a powerful dependency injection system. Find a way to minimize code repetition.
+
+### Sanic
+
+It was one of the first extremely fast Python frameworks based on `asyncio`. It was made to be very similar to Flask.
+
+!!! note "Technical Details"
+ It used `uvloop` instead of the default Python `asyncio` loop. That's what made it so fast.
+
+ It clearly inspired Uvicorn and Starlette, that are currently faster than Sanic in open benchmarks.
+
+!!! check "Inspired **FastAPI** to" Find a way to have a crazy performance.
+
+ That's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).
+
+### Falcon
+
+Falcon is another high performance Python framework, it is designed to be minimal, and work as the foundation of other frameworks like Hug.
+
+It is designed to have functions that receive two parameters, one "request" and one "response". Then you "read" parts from the request, and "write" parts to the response. Because of this design, it is not possible to declare request parameters and bodies with standard Python type hints as function parameters.
+
+So, data validation, serialization, and documentation, have to be done in code, not automatically. Or they have to be implemented as a framework on top of Falcon, like Hug. This same distinction happens in other frameworks that are inspired by Falcon's design, of having one request object and one response object as parameters.
+
+!!! check "Inspired **FastAPI** to" Find ways to get great performance.
+
+ Along with Hug (as Hug is based on Falcon) inspired **FastAPI** to declare a `response` parameter in functions.
+
+ Although in FastAPI it's optional, and is used mainly to set headers, cookies, and alternative status codes.
+
+### Molten
+
+I discovered Molten in the first stages of building **FastAPI**. And it has quite similar ideas:
+
+* Based on Python type hints.
+* Validation and documentation from these types.
+* Dependency Injection system.
+
+It doesn't use a data validation, serialization and documentation third-party library like Pydantic, it has its own. So, these data type definitions would not be reusable as easily.
+
+It requires a little bit more verbose configurations. And as it is based on WSGI (instead of ASGI), it is not designed to take advantage of the high-performance provided by tools like Uvicorn, Starlette and Sanic.
+
+The dependency injection system requires pre-registration of the dependencies and the dependencies are solved based on the declared types. So, it's not possible to declare more than one "component" that provides a certain type.
+
+Routes are declared in a single place, using functions declared in other places (instead of using decorators that can be placed right on top of the function that handles the endpoint). This is closer to how Django does it than to how Flask (and Starlette) does it. It separates in the code things that are relatively tightly coupled.
+
+!!! check "Inspired **FastAPI** to" Define extra validations for data types using the "default" value of model attributes. This improves editor support, and it was not available in Pydantic before.
+
+ This actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).
+
+### Hug
+
+Hug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.
+
+It used custom types in its declarations instead of standard Python types, but it was still a huge step forward.
+
+It also was one of the first frameworks to generate a custom schema declaring the whole API in JSON.
+
+It was not based on a standard like OpenAPI and JSON Schema. So it wouldn't be straightforward to integrate it with other tools, like Swagger UI. But again, it was a very innovative idea.
+
+It has an interesting, uncommon feature: using the same framework, it's possible to create APIs and also CLIs.
+
+As it is based on the previous standard for synchronous Python web frameworks (WSGI), it can't handle Websockets and other things, although it still has high performance too.
+
+!!! info
+ Hug was created by Timothy Crosley, the same creator of `isort`, a great tool to automatically sort imports in Python files.
+
+!!! check "Ideas inspired in **FastAPI**" Hug inspired parts of APIStar, and was one of the tools I found most promising, alongside APIStar.
+
+ Hug helped inspiring **FastAPI** to use Python type hints to declare parameters, and to generate a schema defining the API automatically.
+
+ Hug inspired **FastAPI** to declare a `response` parameter in functions to set headers and cookies.
+
+### APIStar (<= 0.5)
+
+Right before deciding to build **FastAPI** I found **APIStar** server. It had almost everything I was looking for and had a great design.
+
+It was one of the first implementations of a framework using Python type hints to declare parameters and requests that I ever saw (before NestJS and Molten). I found it more or less at the same time as Hug. But APIStar used the OpenAPI standard.
+
+It had automatic data validation, data serialization and OpenAPI schema generation based on the same type hints in several places.
+
+Body schema definitions didn't use the same Python type hints like Pydantic, it was a bit more similar to Marshmallow, so, editor support wouldn't be as good, but still, APIStar was the best available option.
+
+It had the best performance benchmarks at the time (only surpassed by Starlette).
+
+At first, it didn't have an automatic API documentation web UI, but I knew I could add Swagger UI to it.
+
+It had a dependency injection system. It required pre-registration of components, as other tools discussed above. But still, it was a great feature.
+
+I was never able to use it in a full project, as it didn't have security integration, so, I couldn't replace all the features I was having with the full-stack generators based on Flask-apispec. I had in my backlog of projects to create a pull request adding that functionality.
+
+But then, the project's focus shifted.
+
+It was no longer an API web framework, as the creator needed to focus on Starlette.
+
+Now APIStar is a set of tools to validate OpenAPI specifications, not a web framework.
+
+!!! info
+ APIStar was created by Tom Christie. The same guy that created:
+
+ * Django REST Framework
+ * Starlette (in which **FastAPI** is based)
+ * Uvicorn (used by Starlette and **FastAPI**)
+
+!!! check "Inspired **FastAPI** to" Exist.
+
+ The idea of declaring multiple things (data validation, serialization and documentation) with the same Python types, that at the same time provided great editor support, was something I considered a brilliant idea.
+
+ And after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available.
+
+ Then APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**.
+
+ I consider **FastAPI** a "spiritual successor" to APIStar, while improving and increasing the features, typing system, and other parts, based on the learnings from all these previous tools.
+
+## Used by **FastAPI**
+
+### Pydantic
+
+Pydantic is a library to define data validation, serialization and documentation (using JSON Schema) based on Python type hints.
+
+That makes it extremely intuitive.
+
+It is comparable to Marshmallow. Although it's faster than Marshmallow in benchmarks. And as it is based on the same Python type hints, the editor support is great.
+
+!!! check "**FastAPI** uses it to" Handle all the data validation, data serialization and automatic model documentation (based on JSON Schema).
+
+ **FastAPI** then takes that JSON Schema data and puts it in OpenAPI, apart from all the other things it does.
+
+### Starlette
+
+Starlette is a lightweight ASGI framework/toolkit, which is ideal for building high-performance asyncio services.
+
+It is very simple and intuitive. It's designed to be easily extensible, and have modular components.
+
+It has:
+
+* Seriously impressive performance.
+* WebSocket support.
+* In-process background tasks.
+* Startup and shutdown events.
+* Test client built on HTTPX.
+* CORS, GZip, Static Files, Streaming responses.
+* Session and Cookie support.
+* 100% test coverage.
+* 100% type annotated codebase.
+* Few hard dependencies.
+
+Starlette is currently the fastest Python framework tested. Only surpassed by Uvicorn, which is not a framework, but a server.
+
+Starlette provides all the basic web microframework functionality.
+
+But it doesn't provide automatic data validation, serialization or documentation.
+
+That's one of the main things that **FastAPI** adds on top, all based on Python type hints (using Pydantic). That, plus the dependency injection system, security utilities, OpenAPI schema generation, etc.
+
+!!! note "Technical Details"
+ ASGI is a new "standard" being developed by Django core team members. It is still not a "Python standard" (a PEP), although they are in the process of doing that.
+
+ Nevertheless, it is already being used as a "standard" by several tools. This greatly improves interoperability, as you could switch Uvicorn for any other ASGI server (like Daphne or Hypercorn), or you could add ASGI compatible tools, like `python-socketio`.
+
+!!! check "**FastAPI** uses it to" Handle all the core web parts. Adding features on top.
+
+ The class `FastAPI` itself inherits directly from the class `Starlette`.
+
+ So, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids.
+
+### Uvicorn
+
+Uvicorn is a lightning-fast ASGI server, built on uvloop and httptools.
+
+It is not a web framework, but a server. For example, it doesn't provide tools for routing by paths. That's something that a framework like Starlette (or **FastAPI**) would provide on top.
+
+It is the recommended server for Starlette and **FastAPI**.
+
+!!! check "**FastAPI** recommends it as" The main web server to run **FastAPI** applications.
+
+ You can combine it with Gunicorn, to have an asynchronous multi-process server.
+
+ Check more details in the [Deployment](deployment/index.md){.internal-link target=_blank} section.
+
+## Benchmarks and speed
+
+To understand, compare, and see the difference between Uvicorn, Starlette and FastAPI, check the section about [Benchmarks](benchmarks.md){.internal-link target=_blank}.
diff --git a/docs/zh/docs/async.md b/docs/zh/docs/async.md
new file mode 100644
index 0000000000000..3ac62a7795ea9
--- /dev/null
+++ b/docs/zh/docs/async.md
@@ -0,0 +1,430 @@
+# Concurrency and async / await
+
+Details about the `async def` syntax for *path operation functions* and some background about asynchronous code, concurrency, and parallelism.
+
+## In a hurry?
+
+TL;DR:
+
+If you are using third party libraries that tell you to call them with `await`, like:
+
+```Python
+results = await some_library()
+```
+
+Then, declare your *path operation functions* with `async def` like:
+
+```Python hl_lines="2"
+@app.get('/')
+async def read_results():
+ results = await some_library()
+ return results
+```
+
+!!! note
+ You can only use `await` inside of functions created with `async def`.
+
+---
+
+If you are using a third party library that communicates with something (a database, an API, the file system, etc.) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your *path operation functions* as normally, with just `def`, like:
+
+```Python hl_lines="2"
+@app.get('/')
+def results():
+ results = some_library()
+ return results
+```
+
+---
+
+If your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`.
+
+---
+
+If you just don't know, use normal `def`.
+
+---
+
+**Note**: You can mix `def` and `async def` in your *path operation functions* as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.
+
+Anyway, in any of the cases above, FastAPI will still work asynchronously and be extremely fast.
+
+But by following the steps above, it will be able to do some performance optimizations.
+
+## Technical Details
+
+Modern versions of Python have support for **"asynchronous code"** using something called **"coroutines"**, with **`async` and `await`** syntax.
+
+Let's see that phrase by parts in the sections below:
+
+* **Asynchronous Code**
+* **`async` and `await`**
+* **Coroutines**
+
+## Asynchronous Code
+
+Asynchronous code just means that the language 💬 has a way to tell the computer / program 🤖 that at some point in the code, it 🤖 will have to wait for *something else* to finish somewhere else. Let's say that *something else* is called "slow-file" 📝.
+
+So, during that time, the computer can go and do some other work, while "slow-file" 📝 finishes.
+
+Then the computer / program 🤖 will come back every time it has a chance because it's waiting again, or whenever it 🤖 finished all the work it had at that point. And it 🤖 will see if any of the tasks it was waiting for have already finished, doing whatever it had to do.
+
+Next, it 🤖 takes the first task to finish (let's say, our "slow-file" 📝) and continues whatever it had to do with it.
+
+That "wait for something else" normally refers to I/O operations that are relatively "slow" (compared to the speed of the processor and the RAM memory), like waiting for:
+
+* the data from the client to be sent through the network
+* the data sent by your program to be received by the client through the network
+* the contents of a file in the disk to be read by the system and given to your program
+* the contents your program gave to the system to be written to disk
+* a remote API operation
+* a database operation to finish
+* a database query to return the results
+* etc.
+
+As the execution time is consumed mostly by waiting for I/O operations, they call them "I/O bound" operations.
+
+It's called "asynchronous" because the computer / program doesn't have to be "synchronized" with the slow task, waiting for the exact moment that the task finishes, while doing nothing, to be able to take the task result and continue the work.
+
+Instead of that, by being an "asynchronous" system, once finished, the task can wait in line a little bit (some microseconds) for the computer / program to finish whatever it went to do, and then come back to take the results and continue working with them.
+
+For "synchronous" (contrary to "asynchronous") they commonly also use the term "sequential", because the computer / program follows all the steps in sequence before switching to a different task, even if those steps involve waiting.
+
+### Concurrency and Burgers
+
+This idea of **asynchronous** code described above is also sometimes called **"concurrency"**. It is different from **"parallelism"**.
+
+**Concurrency** and **parallelism** both relate to "different things happening more or less at the same time".
+
+But the details between *concurrency* and *parallelism* are quite different.
+
+To see the difference, imagine the following story about burgers:
+
+### Concurrent Burgers
+
+You go with your crush to get fast food, you stand in line while the cashier takes the orders from the people in front of you. 😍
+
+
+
+Then it's your turn, you place your order of 2 very fancy burgers for your crush and you. 🍔🍔
+
+
+
+The cashier says something to the cook in the kitchen so they know they have to prepare your burgers (even though they are currently preparing the ones for the previous clients).
+
+
+
+You pay. 💸
+
+The cashier gives you the number of your turn.
+
+
+
+While you are waiting, you go with your crush and pick a table, you sit and talk with your crush for a long time (as your burgers are very fancy and take some time to prepare).
+
+As you are sitting at the table with your crush, while you wait for the burgers, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.
+
+
+
+While waiting and talking to your crush, from time to time, you check the number displayed on the counter to see if it's your turn already.
+
+Then at some point, it finally is your turn. You go to the counter, get your burgers and come back to the table.
+
+
+
+You and your crush eat the burgers and have a nice time. ✨
+
+
+
+!!! info
+ Beautiful illustrations by Ketrina Thompson. 🎨
+
+---
+
+Imagine you are the computer / program 🤖 in that story.
+
+While you are at the line, you are just idle 😴, waiting for your turn, not doing anything very "productive". But the line is fast because the cashier is only taking the orders (not preparing them), so that's fine.
+
+Then, when it's your turn, you do actual "productive" work, you process the menu, decide what you want, get your crush's choice, pay, check that you give the correct bill or card, check that you are charged correctly, check that the order has the correct items, etc.
+
+But then, even though you still don't have your burgers, your work with the cashier is "on pause" ⏸, because you have to wait 🕙 for your burgers to be ready.
+
+But as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush, and "work" ⏯ 🤓 on that. Then you are again doing something very "productive" as is flirting with your crush 😍.
+
+Then the cashier 💁 says "I'm finished with doing the burgers" by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers because you have the number of your turn, and they have theirs.
+
+So you wait for your crush to finish the story (finish the current work ⏯ / task being processed 🤓), smile gently and say that you are going for the burgers ⏸.
+
+Then you go to the counter 🔀, to the initial task that is now finished ⏯, pick the burgers, say thanks and take them to the table. That finishes that step / task of interaction with the counter ⏹. That in turn, creates a new task, of "eating burgers" 🔀 ⏯, but the previous one of "getting burgers" is finished ⏹.
+
+### Parallel Burgers
+
+Now let's imagine these aren't "Concurrent Burgers", but "Parallel Burgers".
+
+You go with your crush to get parallel fast food.
+
+You stand in line while several (let's say 8) cashiers that at the same time are cooks take the orders from the people in front of you.
+
+Everyone before you is waiting for their burgers to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order.
+
+
+
+Then it's finally your turn, you place your order of 2 very fancy burgers for your crush and you.
+
+You pay 💸.
+
+
+
+The cashier goes to the kitchen.
+
+You wait, standing in front of the counter 🕙, so that no one else takes your burgers before you do, as there are no numbers for turns.
+
+
+
+As you and your crush are busy not letting anyone get in front of you and take your burgers whenever they arrive, you cannot pay attention to your crush. 😞
+
+This is "synchronous" work, you are "synchronized" with the cashier/cook 👨🍳. You have to wait 🕙 and be there at the exact moment that the cashier/cook 👨🍳 finishes the burgers and gives them to you, or otherwise, someone else might take them.
+
+
+
+Then your cashier/cook 👨🍳 finally comes back with your burgers, after a long time waiting 🕙 there in front of the counter.
+
+
+
+You take your burgers and go to the table with your crush.
+
+You just eat them, and you are done. ⏹
+
+
+
+There was not much talk or flirting as most of the time was spent waiting 🕙 in front of the counter. 😞
+
+!!! info
+ Beautiful illustrations by Ketrina Thompson. 🎨
+
+---
+
+In this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush), both waiting 🕙 and dedicating their attention ⏯ to be "waiting on the counter" 🕙 for a long time.
+
+The fast food store has 8 processors (cashiers/cooks). While the concurrent burgers store might have had only 2 (one cashier and one cook).
+
+But still, the final experience is not the best. 😞
+
+---
+
+This would be the parallel equivalent story for burgers. 🍔
+
+For a more "real life" example of this, imagine a bank.
+
+Up to recently, most of the banks had multiple cashiers 👨💼👨💼👨💼👨💼 and a big line 🕙🕙🕙🕙🕙🕙🕙🕙.
+
+All of the cashiers doing all the work with one client after the other 👨💼⏯.
+
+And you have to wait 🕙 in the line for a long time or you lose your turn.
+
+You probably wouldn't want to take your crush 😍 with you to do errands at the bank 🏦.
+
+### Burger Conclusion
+
+In this scenario of "fast food burgers with your crush", as there is a lot of waiting 🕙, it makes a lot more sense to have a concurrent system ⏸🔀⏯.
+
+This is the case for most of the web applications.
+
+Many, many users, but your server is waiting 🕙 for their not-so-good connection to send their requests.
+
+And then waiting 🕙 again for the responses to come back.
+
+This "waiting" 🕙 is measured in microseconds, but still, summing it all, it's a lot of waiting in the end.
+
+That's why it makes a lot of sense to use asynchronous ⏸🔀⏯ code for web APIs.
+
+This kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language.
+
+And that's the same level of performance you get with **FastAPI**.
+
+And as you can have parallelism and asynchronicity at the same time, you get higher performance than most of the tested NodeJS frameworks and on par with Go, which is a compiled language closer to C (all thanks to Starlette).
+
+### Is concurrency better than parallelism?
+
+Nope! That's not the moral of the story.
+
+Concurrency is different than parallelism. And it is better on **specific** scenarios that involve a lot of waiting. Because of that, it generally is a lot better than parallelism for web application development. But not for everything.
+
+So, to balance that out, imagine the following short story:
+
+> You have to clean a big, dirty house.
+
+*Yep, that's the whole story*.
+
+---
+
+There's no waiting 🕙 anywhere, just a lot of work to be done, on multiple places of the house.
+
+You could have turns as in the burgers example, first the living room, then the kitchen, but as you are not waiting 🕙 for anything, just cleaning and cleaning, the turns wouldn't affect anything.
+
+It would take the same amount of time to finish with or without turns (concurrency) and you would have done the same amount of work.
+
+But in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner.
+
+In this scenario, each one of the cleaners (including you) would be a processor, doing their part of the job.
+
+And as most of the execution time is taken by actual work (instead of waiting), and the work in a computer is done by a CPU, they call these problems "CPU bound".
+
+---
+
+Common examples of CPU bound operations are things that require complex math processing.
+
+For example:
+
+* **Audio** or **image processing**.
+* **Computer vision**: an image is composed of millions of pixels, each pixel has 3 values / colors, processing that normally requires computing something on those pixels, all at the same time.
+* **Machine Learning**: it normally requires lots of "matrix" and "vector" multiplications. Think of a huge spreadsheet with numbers and multiplying all of them together at the same time.
+* **Deep Learning**: this is a sub-field of Machine Learning, so, the same applies. It's just that there is not a single spreadsheet of numbers to multiply, but a huge set of them, and in many cases, you use a special processor to build and / or use those models.
+
+### Concurrency + Parallelism: Web + Machine Learning
+
+With **FastAPI** you can take the advantage of concurrency that is very common for web development (the same main attraction of NodeJS).
+
+But you can also exploit the benefits of parallelism and multiprocessing (having multiple processes running in parallel) for **CPU bound** workloads like those in Machine Learning systems.
+
+That, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others).
+
+To see how to achieve this parallelism in production see the section about [Deployment](deployment/index.md){.internal-link target=_blank}.
+
+## `async` and `await`
+
+Modern versions of Python have a very intuitive way to define asynchronous code. This makes it look just like normal "sequential" code and do the "awaiting" for you at the right moments.
+
+When there is an operation that will require waiting before giving the results and has support for these new Python features, you can code it like:
+
+```Python
+burgers = await get_burgers(2)
+```
+
+The key here is the `await`. It tells Python that it has to wait ⏸ for `get_burgers(2)` to finish doing its thing 🕙 before storing the results in `burgers`. With that, Python will know that it can go and do something else 🔀 ⏯ in the meanwhile (like receiving another request).
+
+For `await` to work, it has to be inside a function that supports this asynchronicity. To do that, you just declare it with `async def`:
+
+```Python hl_lines="1"
+async def get_burgers(number: int):
+ # Do some asynchronous stuff to create the burgers
+ return burgers
+```
+
+...instead of `def`:
+
+```Python hl_lines="2"
+# This is not asynchronous
+def get_sequential_burgers(number: int):
+ # Do some sequential stuff to create the burgers
+ return burgers
+```
+
+With `async def`, Python knows that, inside that function, it has to be aware of `await` expressions, and that it can "pause" ⏸ the execution of that function and go do something else 🔀 before coming back.
+
+When you want to call an `async def` function, you have to "await" it. So, this won't work:
+
+```Python
+# This won't work, because get_burgers was defined with: async def
+burgers = get_burgers(2)
+```
+
+---
+
+So, if you are using a library that tells you that you can call it with `await`, you need to create the *path operation functions* that uses it with `async def`, like in:
+
+```Python hl_lines="2-3"
+@app.get('/burgers')
+async def read_burgers():
+ burgers = await get_burgers(2)
+ return burgers
+```
+
+### More technical details
+
+You might have noticed that `await` can only be used inside of functions defined with `async def`.
+
+But at the same time, functions defined with `async def` have to be "awaited". So, functions with `async def` can only be called inside of functions defined with `async def` too.
+
+So, about the egg and the chicken, how do you call the first `async` function?
+
+If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your *path operation function*, and FastAPI will know how to do the right thing.
+
+But if you want to use `async` / `await` without FastAPI, you can do it as well.
+
+### Write your own async code
+
+Starlette (and **FastAPI**) are based on AnyIO, which makes it compatible with both Python's standard library asyncio and Trio.
+
+In particular, you can directly use AnyIO for your advanced concurrency use cases that require more advanced patterns in your own code.
+
+And even if you were not using FastAPI, you could also write your own async applications with AnyIO to be highly compatible and get its benefits (e.g. *structured concurrency*).
+
+### Other forms of asynchronous code
+
+This style of using `async` and `await` is relatively new in the language.
+
+But it makes working with asynchronous code a lot easier.
+
+This same syntax (or almost identical) was also included recently in modern versions of JavaScript (in Browser and NodeJS).
+
+But before that, handling asynchronous code was quite more complex and difficult.
+
+In previous versions of Python, you could have used threads or Gevent. But the code is way more complex to understand, debug, and think about.
+
+In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which leads to callback hell.
+
+## Coroutines
+
+**Coroutine** is just the very fancy term for the thing returned by an `async def` function. Python knows that it is something like a function that it can start and that it will end at some point, but that it might be paused ⏸ internally too, whenever there is an `await` inside of it.
+
+But all this functionality of using asynchronous code with `async` and `await` is many times summarized as using "coroutines". It is comparable to the main key feature of Go, the "Goroutines".
+
+## Conclusion
+
+Let's see the same phrase from above:
+
+> Modern versions of Python have support for **"asynchronous code"** using something called **"coroutines"**, with **`async` and `await`** syntax.
+
+That should make more sense now. ✨
+
+All that is what powers FastAPI (through Starlette) and what makes it have such an impressive performance.
+
+## Very Technical Details
+
+!!! warning
+ You can probably skip this.
+
+ These are very technical details of how **FastAPI** works underneath.
+
+ If you have quite some technical knowledge (co-routines, threads, blocking, etc.) and are curious about how FastAPI handles `async def` vs normal `def`, go ahead.
+
+### Path operation functions
+
+When you declare a *path operation function* with normal `def` instead of `async def`, it is run in an external threadpool that is then awaited, instead of being called directly (as it would block the server).
+
+If you are coming from another async framework that does not work in the way described above and you are used to defining trivial compute-only *path operation functions* with plain `def` for a tiny performance gain (about 100 nanoseconds), please note that in **FastAPI** the effect would be quite opposite. In these cases, it's better to use `async def` unless your *path operation functions* use code that performs blocking I/O.
+
+Still, in both situations, chances are that **FastAPI** will [still be faster](/#performance){.internal-link target=_blank} than (or at least comparable to) your previous framework.
+
+### Dependencies
+
+The same applies for [dependencies](/tutorial/dependencies/index.md){.internal-link target=_blank}. If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool.
+
+### Sub-dependencies
+
+You can have multiple dependencies and [sub-dependencies](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiring each other (as parameters of the function definitions), some of them might be created with `async def` and some with normal `def`. It would still work, and the ones created with normal `def` would be called on an external thread (from the threadpool) instead of being "awaited".
+
+### Other utility functions
+
+Any other utility function that you call directly can be created with normal `def` or `async def` and FastAPI won't affect the way you call it.
+
+This is in contrast to the functions that FastAPI calls for you: *path operation functions* and dependencies.
+
+If your utility function is a normal function with `def`, it will be called directly (as you write it in your code), not in a threadpool, if the function is created with `async def` then you should `await` for that function when you call it in your code.
+
+---
+
+Again, these are very technical details that would probably be useful if you came searching for them.
+
+Otherwise, you should be good with the guidelines from the section above: In a hurry?.
diff --git a/docs/zh/docs/benchmarks.md b/docs/zh/docs/benchmarks.md
index 71e8d483822ac..44ff3a3870998 100644
--- a/docs/zh/docs/benchmarks.md
+++ b/docs/zh/docs/benchmarks.md
@@ -1,6 +1,6 @@
-# 基准测试
+# Benchmarks
-第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 可用的最快的 Python 框架之一,仅次于 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。(*)
+第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 可用的最快的 Python 框架之一,仅次于 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。 (*)
但是在查看基准得分和对比时,请注意以下几点。
@@ -10,7 +10,7 @@
具体来说,是将 Uvicorn,Starlette 和 FastAPI 一起比较(在许多其它工具中)。
-该工具解决的问题最简单,它将获得更好的性能。而且大多数基准测试并未测试该工具提供的其他功能。
+该工具解决的问题最简单,它将获得更好的性能。 而且大多数基准测试并未测试该工具提供的其他功能。
层次结构如下:
@@ -20,15 +20,15 @@
* **Uvicorn**:
* 具有最佳性能,因为除了服务器本身外,它没有太多额外的代码。
- * 您不会直接在 Uvicorn 中编写应用程序。这意味着您的代码至少必须包含 Starlette(或 **FastAPI**)提供的代码。如果您这样做了(即直接在 Uvicorn 中编写应用程序),最终的应用程序会和使用了框架并且最小化了应用代码和 bug 的情况具有相同的性能损耗。
- * 如果要对比与 Uvicorn 对标的服务器,请将其与 Daphne,Hypercorn,uWSGI等应用服务器进行比较。
+ * 您不会直接在 Uvicorn 中编写应用程序。 这意味着您的代码至少必须包含 Starlette(或 **FastAPI**)提供的代码。 如果您这样做了(即直接在 Uvicorn 中编写应用程序),最终的应用程序会和使用了框架并且最小化了应用代码和 bug 的情况具有相同的性能损耗。
+ * 如果要对比与 Uvicorn 对标的服务器,请将其与 Daphne,Hypercorn,uWSGI等应用服务器进行比较。 Application servers.
* **Starlette**:
- * 在 Uvicorn 后使用 Starlette,性能会略有下降。实际上,Starlette 使用 Uvicorn运行。因此,由于必须执行更多的代码,它只会比 Uvicorn 更慢。
+ * 在 Uvicorn 后使用 Starlette,性能会略有下降。 实际上,Starlette 使用 Uvicorn运行。 因此,由于必须执行更多的代码,它只会比 Uvicorn 更慢。
* 但它为您提供了构建简单的网络程序的工具,并具有基于路径的路由等功能。
- * 如果想对比与 Starlette 对标的开发框架,请将其与 Sanic,Flask,Django 等网络框架(或微框架)进行比较。
+ * 如果想对比与 Starlette 对标的开发框架,请将其与 Sanic,Flask,Django 等网络框架(或微框架)进行比较。 Web frameworks (or microframeworks).
* **FastAPI**:
* 与 Starlette 使用 Uvicorn 一样,由于 **FastAPI** 使用 Starlette,因此 FastAPI 不能比 Starlette 更快。
- * FastAPI 在 Starlette 基础上提供了更多功能。例如在开发 API 时,所需的数据验证和序列化功能。FastAPI 可以帮助您自动生成 API文档,(文档在应用程序启动时自动生成,所以不会增加应用程序运行时的开销)。
- * 如果您不使用 FastAPI 而直接使用 Starlette(或诸如 Sanic,Flask,Responder 等其它工具),您则要自己实现所有的数据验证和序列化。那么最终您的应用程序会和使用 FastAPI 构建的程序有相同的开销。一般这种数据验证和序列化的操作在您应用程序的代码中会占很大比重。
+ * FastAPI 在 Starlette 基础上提供了更多功能。 例如在开发 API 时,所需的数据验证和序列化功能。 FastAPI 可以帮助您自动生成 API文档,(文档在应用程序启动时自动生成,所以不会增加应用程序运行时的开销)。
+ * 如果您不使用 FastAPI 而直接使用 Starlette(或诸如 Sanic,Flask,Responder 等其它工具),您则要自己实现所有的数据验证和序列化。 那么最终您的应用程序会和使用 FastAPI 构建的程序有相同的开销。 一般这种数据验证和序列化的操作在您应用程序的代码中会占很大比重。
* 因此,通过使用 FastAPI 意味着您可以节省开发时间,减少编码错误,用更少的编码实现其功能,并且相比不使用 FastAPI 您很大可能会获得相同或更好的性能(因为那样您必须在代码中实现所有相同的功能)。
- * 如果您想对比与 FastAPI 对标的开发框架,请与能够提供数据验证,序列化和带有自动文档生成的网络应用程序框架(或工具集)进行对比,例如具有集成自动数据验证,序列化和自动化文档的 Flask-apispec,NestJS,Molten 等。
+ * 如果您想对比与 FastAPI 对标的开发框架,请与能够提供数据验证,序列化和带有自动文档生成的网络应用程序框架(或工具集)进行对比,例如具有集成自动数据验证,序列化和自动化文档的 Flask-apispec,NestJS,Molten 等。 Frameworks with integrated automatic data validation, serialization and documentation.
diff --git a/docs/zh/docs/contributing.md b/docs/zh/docs/contributing.md
index 4ebd673150b25..46f349f032fab 100644
--- a/docs/zh/docs/contributing.md
+++ b/docs/zh/docs/contributing.md
@@ -32,6 +32,7 @@ $ python -m venv env
$ source ./env/bin/activate
```
+
=== "Windows PowerShell"
@@ -42,18 +43,20 @@ $ python -m venv env
$ .\env\Scripts\Activate.ps1
```
+
=== "Windows Bash"
Or if you use Bash for Windows (e.g. Git Bash):
-
+
+
+---
+
+Now that we know the difference between the terms **process** and **program**, let's continue talking about deployments.
+
+## Running on Startup
+
+In most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only in certain situations, but most of the time you want it constantly running and **available**.
+
+### In a Remote Server
+
+When you set up a remote server (a cloud server, a virtual machine, etc.) the simplest thing you can do is to run Uvicorn (or similar) manually, the same way you do when developing locally.
+
+And it will work and will be useful **during development**.
+
+But if your connection to the server is lost, the **running process** will probably die.
+
+And if the server is restarted (for example after updates, or migrations from the cloud provider) you probably **won't notice it**. And because of that, you won't even know that you have to restart the process manually. So, your API will just stay dead. 😱
+
+### Run Automatically on Startup
+
+In general, you will probably want the server program (e.g. Uvicorn) to be started automatically on server startup, and without needing any **human intervention**, to have a process always running with your API (e.g. Uvicorn running your FastAPI app).
+
+### Separate Program
+
+To achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases, it would also make sure other components or applications are also run, for example, a database.
+
+### Example Tools to Run at Startup
+
+Some examples of the tools that can do this job are:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker in Swarm Mode
+* Systemd
+* Supervisor
+* Handled internally by a cloud provider as part of their services
+* Others...
+
+I'll give you more concrete examples in the next chapters.
+
+## Restarts
+
+Similar to making sure your application is run on startup, you probably also want to make sure it is **restarted** after failures.
+
+### We Make Mistakes
+
+We, as humans, make **mistakes**, all the time. Software almost *always* has **bugs** hidden in different places. 🐛
+
+And we as developers keep improving the code as we find those bugs and as we implement new features (possibly adding new bugs too 😅).
+
+### Small Errors Automatically Handled
+
+When building web APIs with FastAPI, if there's an error in our code, FastAPI will normally contain it to the single request that triggered the error. 🛡
+
+The client will get a **500 Internal Server Error** for that request, but the application will continue working for the next requests instead of just crashing completely.
+
+### Bigger Errors - Crashes
+
+Nevertheless, there might be cases where we write some code that **crashes the entire application** making Uvicorn and Python crash. 💥
+
+And still, you would probably not want the application to stay dead because there was an error in one place, you probably want it to **continue running** at least for the *path operations* that are not broken.
+
+### Restart After Crash
+
+But in those cases with really bad errors that crash the running **process**, you would want an external component that is in charge of **restarting** the process, at least a couple of times...
+
+!!! tip
+ ...Although if the whole application is just **crashing immediately** it probably doesn't make sense to keep restarting it forever. But in those cases, you will probably notice it during development, or at least right after deployment.
+
+ So let's focus on the main cases, where it could crash entirely in some particular cases **in the future**, and it still makes sense to restart it.
+
+You would probably want to have the thing in charge of restarting your application as an **external component**, because by that point, the same application with Uvicorn and Python already crashed, so there's nothing in the same code of the same app that could do anything about it.
+
+### Example Tools to Restart Automatically
+
+In most cases, the same tool that is used to **run the program on startup** is also used to handle automatic **restarts**.
+
+For example, this could be handled by:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker in Swarm Mode
+* Systemd
+* Supervisor
+* Handled internally by a cloud provider as part of their services
+* Others...
+
+## Replication - Processes and Memory
+
+With a FastAPI application, using a server program like Uvicorn, running it once in **one process** can serve multiple clients concurrently.
+
+But in many cases, you will want to run several worker processes at the same time.
+
+### Multiple Processes - Workers
+
+If you have more clients than what a single process can handle (for example if the virtual machine is not too big) and you have **multiple cores** in the server's CPU, then you could have **multiple processes** running with the same application at the same time, and distribute all the requests among them.
+
+When you run **multiple processes** of the same API program, they are commonly called **workers**.
+
+### Worker Processes and Ports
+
+Remember from the docs [About HTTPS](./https.md){.internal-link target=_blank} that only one process can be listening on one combination of port and IP address in a server?
+
+This is still true.
+
+So, to be able to have **multiple processes** at the same time, there has to be a **single process listening on a port** that then transmits the communication to each worker process in some way.
+
+### Memory per Process
+
+Now, when the program loads things in memory, for example, a machine learning model in a variable, or the contents of a large file in a variable, all that **consumes a bit of the memory (RAM)** of the server.
+
+And multiple processes normally **don't share any memory**. This means that each running process has its own things, variables, and memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory.
+
+### Server Memory
+
+For example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB of RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So in total, your API will consume **4 GB of RAM**.
+
+And if your remote server or virtual machine only has 3 GB of RAM, trying to load more than 4 GB of RAM will cause problems. 🚨
+
+### Multiple Processes - An Example
+
+In this example, there's a **Manager Process** that starts and controls two **Worker Processes**.
+
+This Manager Process would probably be the one listening on the **port** in the IP. And it would transmit all the communication to the worker processes.
+
+Those worker processes would be the ones running your application, they would perform the main computations to receive a **request** and return a **response**, and they would load anything you put in variables in RAM.
+
+
+
+Now run `space login` from the Space CLI. Upon pasting the token into the CLI prompt and pressing enter, you should see a confirmation message.
+
+
+
+Click on the new app called `fastapi-deta`, and it will open your API in a new browser tab on a URL like `https://fastapi-deta-gj7ka8.deta.app/`.
+
+You will get a JSON response from your FastAPI app:
+
+```JSON
+{
+ "Hello": "World"
+}
+```
+
+And now you can head over to the `/docs` of your API. For this example, it would be `https://fastapi-deta-gj7ka8.deta.app/docs`.
+
+
+
+## Enable public access
+
+Deta will handle authentication for your account using cookies. By default, every app or API that you `push` or install to your Space is personal - it's only accessible to you.
+
+But you can also make your API public using the `Spacefile` from earlier.
+
+With a `public_routes` parameter, you can specify which paths of your API should be available to the public.
+
+Set your `public_routes` to `"*"` to open every route of your API to the public:
+
+```yaml
+v: 0
+micros:
+ - name: fastapi-deta
+ src: .
+ engine: python3.9
+ public_routes:
+ - "/*"
+```
+
+Then run `space push` again to update your live API on Deta Space.
+
+Once it deploys, you can share your URL with anyone and they will be able to access your API. 🚀
+
+## HTTPS
+
+Congrats! You deployed your FastAPI app to Deta Space! 🎉 🍰
+
+Also, notice that Deta Space correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your users will have a secure encrypted connection. ✅ 🔒
+
+## Create a release
+
+Space also allows you to publish your API. When you publish it, anyone else can install their own copy of your API, in their own Deta Space cloud.
+
+To do so, run `space release` in the Space CLI to create an **unlisted release**:
+
+
+
+## Learn more
+
+At some point, you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base and Deta Drive, both of which have a generous **free tier**.
+
+You can also read more in the Deta Space Documentation.
+
+!!! tip
+ If you have any Deta related questions, comments, or feedback, head to the Deta Discord server.
+
+
+## Deployment Concepts
+
+Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md){.internal-link target=_blank}, here's how each of them would be handled with Deta Space:
+
+- **HTTPS**: Handled by Deta Space, they will give you a subdomain and handle HTTPS automatically.
+- **Running on startup**: Handled by Deta Space, as part of their service.
+- **Restarts**: Handled by Deta Space, as part of their service.
+- **Replication**: Handled by Deta Space, as part of their service.
+- **Authentication**: Handled by Deta Space, as part of their service.
+- **Memory**: Limit predefined by Deta Space, you could contact them to increase it.
+- **Previous steps before starting**: Can be configured using the `Spacefile`.
+
+!!! note
+ Deta Space is designed to make it easy and free to build cloud applications for yourself. Then you can optionally share them with anyone.
+
+ It can simplify several use cases, but at the same time, it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc.
+
+ You can read more details in the Deta Space Documentation to see if it's the right choice for you.
diff --git a/docs/zh/docs/deployment/docker.md b/docs/zh/docs/deployment/docker.md
new file mode 100644
index 0000000000000..fac4650a2626e
--- /dev/null
+++ b/docs/zh/docs/deployment/docker.md
@@ -0,0 +1,698 @@
+# FastAPI in Containers - Docker
+
+When deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using **Docker**. You can then deploy that container image in one of a few possible ways.
+
+Using Linux containers has several advantages including **security**, **replicability**, **simplicity**, and others.
+
+!!! tip
+ In a hurry and already know this stuff? Jump to the [`Dockerfile` below 👇](#build-a-docker-image-for-fastapi).
+
++ **FastAPI** wouldn't exist if not for the previous work of others. + + There have been many tools created before that have helped inspire its creation. + + I have been avoiding the creation of a new framework for several years. First I tried to solve all the features covered by **FastAPI** using many different frameworks, plug-ins, and tools. + + But at some point, there was no other option than creating something that provided all these features, taking the best ideas from previous tools, and combining them in the best way possible, using language features that weren't even available before (Python 3.6+ type hints). ++ +## Investigation + +By using all the previous alternatives I had the chance to learn from all of them, take ideas, and combine them in the best way I could find for myself and the teams of developers I have worked with. + +For example, it was clear that ideally it should be based on standard Python type hints. + +Also, the best approach was to use already existing standards. + +So, before even starting to code **FastAPI**, I spent several months studying the specs for OpenAPI, JSON Schema, OAuth2, etc. Understanding their relationship, overlap, and differences. + +## Design + +Then I spent some time designing the developer "API" I wanted to have as a user (as a developer using FastAPI). + +I tested several ideas in the most popular Python editors: PyCharm, VS Code, Jedi based editors. + +By the last Python Developer Survey, that covers about 80% of the users. + +It means that **FastAPI** was specifically tested with the editors used by 80% of the Python developers. And as most of the other editors tend to work similarly, all its benefits should work for virtually all editors. + +That way I could find the best ways to reduce code duplication as much as possible, to have completion everywhere, type and error checks, etc. + +All in a way that provided the best development experience for all the developers. + +## Requirements + +After testing several alternatives, I decided that I was going to use **Pydantic** for its advantages. + +Then I contributed to it, to make it fully compliant with JSON Schema, to support different ways to define constraint declarations, and to improve editor support (type checks, autocompletion) based on the tests in several editors. + +During the development, I also contributed to **Starlette**, the other key requirement. + +## Development + +By the time I started creating **FastAPI** itself, most of the pieces were already in place, the design was defined, the requirements and tools were ready, and the knowledge about the standards and specifications was clear and fresh. + +## Future + +By this point, it's already clear that **FastAPI** with its ideas is being useful for many people. + +It is being chosen over previous alternatives for suiting many use cases better. + +Many developers and teams already depend on **FastAPI** for their projects (including me and my team). + +But still, there are many improvements and features to come. + +**FastAPI** has a great future ahead. + +And [your help](help-fastapi.md){.internal-link target=_blank} is greatly appreciated. diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 1de2a8d36d09a..ebd74bc8f00d2 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -2,43 +2,45 @@
- FastAPI 框架,高性能,易于学习,高效编码,生产可用 + FastAPI framework, high performance, easy to learn, fast to code, ready for production
--- -**文档**: https://fastapi.tiangolo.com +**Documentation**: https://fastapi.tiangolo.com -**源码**: https://github.com/tiangolo/fastapi +**Source Code**: https://github.com/tiangolo/fastapi --- -FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.6+ 并基于标准的 Python 类型提示。 +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. -关键特性: +The key features are: -* **快速**:可与 **NodeJS** 和 **Go** 并肩的极高性能(归功于 Starlette 和 Pydantic)。[最快的 Python web 框架之一](#_11)。 +* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance). +* **Fast to code**: Increase the speed to develop features by about 200% to 300%. * +* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema. -* **高效编码**:提高功能开发速度约 200% 至 300%。* -* **更少 bug**:减少约 40% 的人为(开发者)导致错误。* -* **智能**:极佳的编辑器支持。处处皆可自动补全,减少调试时间。 -* **简单**:设计的易于使用和学习,阅读文档的时间更短。 -* **简短**:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。 -* **健壮**:生产可用级别的代码。还有自动生成的交互式文档。 -* **标准化**:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema。 - -* 根据对某个构建线上应用的内部开发团队所进行的测试估算得出。 +* estimation based on tests on an internal development team, building production applications. ## Sponsors @@ -57,64 +59,70 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框 Other sponsors -## 评价 +## Opinions -「_[...] 最近我一直在使用 **FastAPI**。[...] 实际上我正在计划将其用于我所在的**微软**团队的所有**机器学习服务**。其中一些服务正被集成进核心 **Windows** 产品和一些 **Office** 产品。_」 +"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._" -async def...async def...uvicorn main:app --reload 命令......uvicorn main:app --reload...email_validator - 用于 email 校验。
+* email_validator - for email validation.
+* pydantic-settings - for settings management.
+* pydantic-extra-types - for extra types to be used with Pydantic.
-用于 Starlette:
+Used by Starlette:
-* httpx - 使用 `TestClient` 时安装。
-* jinja2 - 使用默认模板配置时安装。
-* python-multipart - 需要通过 `request.form()` 对表单进行「解析」时安装。
-* itsdangerous - 需要 `SessionMiddleware` 支持时安装。
-* pyyaml - 使用 Starlette 提供的 `SchemaGenerator` 时安装(有 FastAPI 你可能并不需要它)。
-* graphene - 需要 `GraphQLApp` 支持时安装。
-* ujson - 使用 `UJSONResponse` 时安装。
+* httpx - Required if you want to use the `TestClient`.
+* jinja2 - Required if you want to use the default template configuration.
+* python-multipart - Required if you want to support form "parsing", with `request.form()`.
+* itsdangerous - Required for `SessionMiddleware` support.
+* pyyaml - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* ujson - Required if you want to use `UJSONResponse`.
-用于 FastAPI / Starlette:
+Used by FastAPI / Starlette:
-* uvicorn - 用于加载和运行你的应用程序的服务器。
-* orjson - 使用 `ORJSONResponse` 时安装。
+* uvicorn - for the server that loads and serves your application.
+* orjson - Required if you want to use `ORJSONResponse`.
-你可以通过 `pip install fastapi[all]` 命令来安装以上所有依赖。
+You can install all of these with `pip install "fastapi[all]"`.
-## 许可协议
+## License
-该项目遵循 MIT 许可协议。
+This project is licensed under the terms of the MIT license.
diff --git a/docs/zh/docs/newsletter.md b/docs/zh/docs/newsletter.md
new file mode 100644
index 0000000000000..782db1353c8d0
--- /dev/null
+++ b/docs/zh/docs/newsletter.md
@@ -0,0 +1,5 @@
+# FastAPI and friends newsletter
+
+
+
+
diff --git a/docs/zh/docs/project-generation.md b/docs/zh/docs/project-generation.md
new file mode 100644
index 0000000000000..8ba34fa11200d
--- /dev/null
+++ b/docs/zh/docs/project-generation.md
@@ -0,0 +1,84 @@
+# Project Generation - Template
+
+You can use a project generator to get started, as it includes a lot of the initial set up, security, database and some API endpoints already done for you.
+
+A project generator will always have a very opinionated setup that you should update and adapt for your own needs, but it might be a good starting point for your project.
+
+## Full Stack FastAPI PostgreSQL
+
+GitHub: https://github.com/tiangolo/full-stack-fastapi-postgresql
+
+### Full Stack FastAPI PostgreSQL - Features
+
+* Full **Docker** integration (Docker based).
+* Docker Swarm Mode deployment.
+* **Docker Compose** integration and optimization for local development.
+* **Production ready** Python web server using Uvicorn and Gunicorn.
+* Python **FastAPI** backend:
+ * **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic).
+ * **Intuitive**: Great editor support. Completion everywhere. Less time debugging.
+ * **Easy**: Designed to be easy to use and learn. Less time reading docs.
+ * **Short**: Minimize code duplication. Multiple features from each parameter declaration.
+ * **Robust**: Get production-ready code. With automatic interactive documentation.
+ * **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI and JSON Schema.
+ * **Many other features** including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
+* **Secure password** hashing by default.
+* **JWT token** authentication.
+* **SQLAlchemy** models (independent of Flask extensions, so they can be used with Celery workers directly).
+* Basic starting models for users (modify and remove as you need).
+* **Alembic** migrations.
+* **CORS** (Cross Origin Resource Sharing).
+* **Celery** worker that can import and use models and code from the rest of the backend selectively.
+* REST backend tests based on **Pytest**, integrated with Docker, so you can test the full API interaction, independent on the database. As it runs in Docker, it can build a new data store from scratch each time (so you can use ElasticSearch, MongoDB, CouchDB, or whatever you want, and just test that the API works).
+* Easy Python integration with **Jupyter Kernels** for remote or in-Docker development with extensions like Atom Hydrogen or Visual Studio Code Jupyter.
+* **Vue** frontend:
+ * Generated with Vue CLI.
+ * **JWT Authentication** handling.
+ * Login view.
+ * After login, main dashboard view.
+ * Main dashboard with user creation and edition.
+ * Self user edition.
+ * **Vuex**.
+ * **Vue-router**.
+ * **Vuetify** for beautiful material design components.
+ * **TypeScript**.
+ * Docker server based on **Nginx** (configured to play nicely with Vue-router).
+ * Docker multi-stage building, so you don't need to save or commit compiled code.
+ * Frontend tests ran at build time (can be disabled too).
+ * Made as modular as possible, so it works out of the box, but you can re-generate with Vue CLI or create it as you need, and re-use what you want.
+* **PGAdmin** for PostgreSQL database, you can modify it to use PHPMyAdmin and MySQL easily.
+* **Flower** for Celery jobs monitoring.
+* Load balancing between frontend and backend with **Traefik**, so you can have both under the same domain, separated by path, but served by different containers.
+* Traefik integration, including Let's Encrypt **HTTPS** certificates automatic generation.
+* GitLab **CI** (continuous integration), including frontend and backend testing.
+
+## Full Stack FastAPI Couchbase
+
+GitHub: https://github.com/tiangolo/full-stack-fastapi-couchbase
+
+⚠️ **WARNING** ⚠️
+
+If you are starting a new project from scratch, check the alternatives here.
+
+For example, the project generator Full Stack FastAPI PostgreSQL might be a better alternative, as it is actively maintained and used. And it includes all the new features and improvements.
+
+You are still free to use the Couchbase-based generator if you want to, it should probably still work fine, and if you already have a project generated with it that's fine as well (and you probably already updated it to suit your needs).
+
+You can read more about it in the docs for the repo.
+
+## Full Stack FastAPI MongoDB
+
+...might come later, depending on my time availability and other factors. 😅 🎉
+
+## Machine Learning models with spaCy and FastAPI
+
+GitHub: https://github.com/microsoft/cookiecutter-spacy-fastapi
+
+### Machine Learning models with spaCy and FastAPI - Features
+
+* **spaCy** NER model integration.
+* **Azure Cognitive Search** request format built in.
+* **Production ready** Python web server using Uvicorn and Gunicorn.
+* **Azure DevOps** Kubernetes (AKS) CI/CD deployment built in.
+* **Multilingual** Easily choose one of spaCy's built in languages during project setup.
+* **Easily extensible** to other model frameworks (Pytorch, Tensorflow), not just spaCy.
diff --git a/docs/zh/docs/python-types.md b/docs/zh/docs/python-types.md
index 6cdb4b58838d7..34350d70befba 100644
--- a/docs/zh/docs/python-types.md
+++ b/docs/zh/docs/python-types.md
@@ -1,139 +1,139 @@
-# Python 类型提示简介
+# Python Types Intro
-**Python 3.6+ 版本**加入了对"类型提示"的支持。
+Python has support for optional "type hints" (also called "type annotations").
-这些**"类型提示"**是一种新的语法(在 Python 3.6 版本加入)用来声明一个变量的类型。
+These **"type hints"** or annotations are a special syntax that allow declaring the type of a variable.
-通过声明变量的类型,编辑器和一些工具能给你提供更好的支持。
+By declaring types for your variables, editors and tools can give you better support.
-这只是一个关于 Python 类型提示的**快速入门 / 复习**。它仅涵盖与 **FastAPI** 一起使用所需的最少部分...实际上只有很少一点。
+This is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.
-整个 **FastAPI** 都基于这些类型提示构建,它们带来了许多优点和好处。
+**FastAPI** is all based on these type hints, they give it many advantages and benefits.
-但即使你不会用到 **FastAPI**,了解一下类型提示也会让你从中受益。
+But even if you never use **FastAPI**, you would benefit from learning a bit about them.
!!! note
- 如果你已经精通 Python,并且了解关于类型提示的一切知识,直接跳到下一章节吧。
+ If you are a Python expert, and you already know everything about type hints, skip to the next chapter.
-## 动机
+## Motivation
-让我们从一个简单的例子开始:
+Let's start with a simple example:
```Python
{!../../../docs_src/python_types/tutorial001.py!}
```
-运行这段程序将输出:
+Calling this program outputs:
```
John Doe
```
-这个函数做了下面这些事情:
+The function does the following:
-* 接收 `first_name` 和 `last_name` 参数。
-* 通过 `title()` 将每个参数的第一个字母转换为大写形式。
-* 中间用一个空格来拼接它们。
+* Takes a `first_name` and `last_name`.
+* Converts the first letter of each one to upper case with `title()`.
+* Concatenates them with a space in the middle.
```Python hl_lines="2"
{!../../../docs_src/python_types/tutorial001.py!}
```
-### 修改示例
+### Edit it
-这是一个非常简单的程序。
+It's a very simple program.
-现在假设你将从头开始编写这段程序。
+But now imagine that you were writing it from scratch.
-在某一时刻,你开始定义函数,并且准备好了参数...。
+At some point you would have started the definition of the function, you had the parameters ready...
-现在你需要调用一个"将第一个字母转换为大写形式的方法"。
+But then you have to call "that method that converts the first letter to upper case".
-等等,那个方法是什么来着?`upper`?还是 `uppercase`?`first_uppercase`?`capitalize`?
+Was it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?
-然后你尝试向程序员老手的朋友——编辑器自动补全寻求帮助。
+Then, you try with the old programmer's friend, editor autocompletion.
-输入函数的第一个参数 `first_name`,输入点号(`.`)然后敲下 `Ctrl+Space` 来触发代码补全。
+You type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.
-但遗憾的是并没有起什么作用:
+But, sadly, you get nothing useful:
-
+
-### 添加类型
+### Add types
-让我们来修改上面例子的一行代码。
+Let's modify a single line from the previous version.
-我们将把下面这段代码中的函数参数从:
+We will change exactly this fragment, the parameters of the function, from:
```Python
first_name, last_name
```
-改成:
+to:
```Python
first_name: str, last_name: str
```
-就是这样。
+That's it.
-这些就是"类型提示":
+Those are the "type hints":
```Python hl_lines="1"
{!../../../docs_src/python_types/tutorial002.py!}
```
-这和声明默认值是不同的,例如:
+That is not the same as declaring default values like would be with:
```Python
first_name="john", last_name="doe"
```
-这两者不一样。
+It's a different thing.
-我们用的是冒号(`:`),不是等号(`=`)。
+We are using colons (`:`), not equals (`=`).
-而且添加类型提示一般不会改变原来的运行结果。
+And adding type hints normally doesn't change what happens from what would happen without them.
-现在假设我们又一次正在创建这个函数,这次添加了类型提示。
+But now, imagine you are again in the middle of creating that function, but with type hints.
-在同样的地方,通过 `Ctrl+Space` 触发自动补全,你会发现:
+At the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:
-
+
-这样,你可以滚动查看选项,直到你找到看起来眼熟的那个:
+With that, you can scroll, seeing the options, until you find the one that "rings a bell":
-
+
-## 更多动机
+## More motivation
-下面是一个已经有类型提示的函数:
+Check this function, it already has type hints:
```Python hl_lines="1"
{!../../../docs_src/python_types/tutorial003.py!}
```
-因为编辑器已经知道了这些变量的类型,所以不仅能对代码进行补全,还能检查其中的错误:
+Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
-
+
-现在你知道了必须先修复这个问题,通过 `str(age)` 把 `age` 转换成字符串:
+Now you know that you have to fix it, convert `age` to a string with `str(age)`:
```Python hl_lines="2"
{!../../../docs_src/python_types/tutorial004.py!}
```
-## 声明类型
+## Declaring types
-你刚刚看到的就是声明类型提示的主要场景。用于函数的参数。
+You just saw the main place to declare type hints. As function parameters.
-这也是你将在 **FastAPI** 中使用它们的主要场景。
+This is also the main place you would use them with **FastAPI**.
-### 简单类型
+### Simple types
-不只是 `str`,你能够声明所有的标准 Python 类型。
+You can declare all the standard Python types, not only `str`.
-比如以下类型:
+You can use, for example:
* `int`
* `float`
@@ -144,143 +144,395 @@ John Doe
{!../../../docs_src/python_types/tutorial005.py!}
```
-### 嵌套类型
+### Generic types with type parameters
-有些容器数据结构可以包含其他的值,比如 `dict`、`list`、`set` 和 `tuple`。它们内部的值也会拥有自己的类型。
+There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too.
-你可以使用 Python 的 `typing` 标准库来声明这些类型以及子类型。
+These types that have internal types are called "**generic**" types. And it's possible to declare them, even with their internal types.
-它专门用来支持这些类型提示。
+To declare those types and the internal types, you can use the standard Python module `typing`. It exists specifically to support these type hints.
-#### 列表
+#### Newer versions of Python
-例如,让我们来定义一个由 `str` 组成的 `list` 变量。
+The syntax using `typing` is **compatible** with all versions, from Python 3.6 to the latest ones, including Python 3.9, Python 3.10, etc.
-从 `typing` 模块导入 `List`(注意是大写的 `L`):
+As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations.
-```Python hl_lines="1"
-{!../../../docs_src/python_types/tutorial006.py!}
-```
+If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity.
-同样以冒号(`:`)来声明这个变量。
+In all the docs there are examples compatible with each version of Python (when there's a difference).
-输入 `List` 作为类型。
+For example "**Python 3.6+**" means it's compatible with Python 3.6 or above (including 3.7, 3.8, 3.9, 3.10, etc). And "**Python 3.9+**" means it's compatible with Python 3.9 or above (including 3.10, etc).
-由于列表是带有"子类型"的类型,所以我们把子类型放在方括号中:
+If you can use the **latest versions of Python**, use the examples for the latest version, those will have the **best and simplest syntax**, for example, "**Python 3.10+**".
-```Python hl_lines="4"
-{!../../../docs_src/python_types/tutorial006.py!}
-```
+#### List
+
+For example, let's define a variable to be a `list` of `str`.
+
+=== "Python 3.9+"
+
+ Declare the variable, with the same colon (`:`) syntax.
+
+ As the type, put `list`.
+
+ As the list is a type that contains some internal types, you put them in square brackets:
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ From `typing`, import `List` (with a capital `L`):
+
+ ``` Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+
+ Declare the variable, with the same colon (`:`) syntax.
+
+ As the type, put the `List` that you imported from `typing`.
+
+ As the list is a type that contains some internal types, you put them in square brackets:
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+!!! info
+ Those internal types in the square brackets are called "type parameters".
+
+ In this case, `str` is the type parameter passed to `List` (or `list` in Python 3.9 and above).
+
+That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
+
+!!! tip
+ If you use Python 3.9 or above, you don't have to import `List` from `typing`, you can use the same regular `list` type instead.
+
+By doing that, your editor can provide support even while processing items from the list:
+
+
+
+Without types, that's almost impossible to achieve.
+
+Notice that the variable `item` is one of the elements in the list `items`.
+
+And still, the editor knows it is a `str`, and provides support for that.
+
+#### Tuple and Set
+
+You would do the same to declare `tuple`s and `set`s:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial007_py39.py!}
+ ```
-这表示:"变量 `items` 是一个 `list`,并且这个列表里的每一个元素都是 `str`"。
+=== "Python 3.6+"
-这样,即使在处理列表中的元素时,你的编辑器也可以提供支持。
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial007.py!}
+ ```
-没有类型,几乎是不可能实现下面这样:
+This means:
-
+* The variable `items_t` is a `tuple` with 3 items, an `int`, another `int`, and a `str`.
+* The variable `items_s` is a `set`, and each of its items is of type `bytes`.
-注意,变量 `item` 是列表 `items` 中的元素之一。
+#### Dict
-而且,编辑器仍然知道它是一个 `str`,并为此提供了支持。
+To define a `dict`, you pass 2 type parameters, separated by commas.
-#### 元组和集合
+The first type parameter is for the keys of the `dict`.
-声明 `tuple` 和 `set` 的方法也是一样的:
+The second type parameter is for the values of the `dict`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008.py!}
+ ```
+
+This means:
+
+* The variable `prices` is a `dict`:
+ * The keys of this `dict` are of type `str` (let's say, the name of each item).
+ * The values of this `dict` are of type `float` (let's say, the price of each item).
+
+#### Union
+
+You can declare that a variable can be any of **several types**, for example, an `int` or a `str`.
+
+In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept.
+
+In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a vertical bar (`|`).
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008b_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008b.py!}
+ ```
+
+In both cases this means that `item` could be an `int` or a `str`.
+
+#### Possibly `None`
+
+You can declare that a value could have a type, like `str`, but that it could also be `None`.
+
+In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module.
```Python hl_lines="1 4"
-{!../../../docs_src/python_types/tutorial007.py!}
+{!../../../docs_src/python_types/tutorial009.py!}
```
-这表示:
+Using `Optional[str]` instead of just `str` will let the editor help you detecting errors where you could be assuming that a value is always a `str`, when it could actually be `None` too.
+
+`Optional[Something]` is actually a shortcut for `Union[Something, None]`, they are equivalent.
+
+This also means that in Python 3.10, you can use `Something | None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial009_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009.py!}
+ ```
+
+=== "Python 3.6+ alternative"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009b.py!}
+ ```
+
+#### Using `Union` or `Optional`
-* 变量 `items_t` 是一个 `tuple`,其中的前两个元素都是 `int` 类型, 最后一个元素是 `str` 类型。
-* 变量 `items_s` 是一个 `set`,其中的每个元素都是 `bytes` 类型。
+If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
-#### 字典
+* 🚨 Avoid using `Optional[SomeType]`
+* Instead ✨ **use `Union[SomeType, None]`** ✨.
-定义 `dict` 时,需要传入两个子类型,用逗号进行分隔。
+Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required.
-第一个子类型声明 `dict` 的所有键。
+I think `Union[SomeType, None]` is more explicit about what it means.
-第二个子类型声明 `dict` 的所有值:
+It's just about the words and names. But those words can affect how you and your teammates think about the code.
+
+As an example, let's take this function:
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009c.py!}
+```
+
+The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
+
+```Python
+say_hi() # Oh, no, this throws an error! 😱
+```
+
+The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value:
+
+```Python
+say_hi(name=None) # This works, None is valid 🎉
+```
+
+The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types:
```Python hl_lines="1 4"
-{!../../../docs_src/python_types/tutorial008.py!}
+{!../../../docs_src/python_types/tutorial009c_py310.py!}
```
-这表示:
+And then you won't have to worry about names like `Optional` and `Union`. 😎
+
+#### Generic types
+
+These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example:
+
+=== "Python 3.10+"
+
+ You can use the same builtin types as generics (with square brackets and types inside):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ And the same as with Python 3.6, from the `typing` module:
+
+ * `Union`
+ * `Optional` (the same as with Python 3.6)
+ * ...and others.
+
+ In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types, that's a lot better and simpler.
+
+=== "Python 3.9+"
+
+ You can use the same builtin types as generics (with square brackets and types inside):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ And the same as with Python 3.6, from the `typing` module:
+
+ * `Union`
+ * `Optional`
+ * ...and others.
+
+=== "Python 3.6+"
-* 变量 `prices` 是一个 `dict`:
- * 这个 `dict` 的所有键为 `str` 类型(可以看作是字典内每个元素的名称)。
- * 这个 `dict` 的所有值为 `float` 类型(可以看作是字典内每个元素的价格)。
+ * `List`
+ * `Tuple`
+ * `Set`
+ * `Dict`
+ * `Union`
+ * `Optional`
+ * ...and others.
-### 类作为类型
+### Classes as types
-你也可以将类声明为变量的类型。
+You can also declare a class as the type of a variable.
-假设你有一个名为 `Person` 的类,拥有 name 属性:
+Let's say you have a class `Person`, with a name:
```Python hl_lines="1-3"
{!../../../docs_src/python_types/tutorial010.py!}
```
-接下来,你可以将一个变量声明为 `Person` 类型:
+Then you can declare a variable to be of type `Person`:
```Python hl_lines="6"
{!../../../docs_src/python_types/tutorial010.py!}
```
-然后,你将再次获得所有的编辑器支持:
+And then, again, you get all the editor support:
-
+
-## Pydantic 模型
+Notice that this means "`one_person` is an **instance** of the class `Person`".
-Pydantic 是一个用来用来执行数据校验的 Python 库。
+It doesn't mean "`one_person` is the **class** called `Person`".
-你可以将数据的"结构"声明为具有属性的类。
+## Pydantic models
-每个属性都拥有类型。
+Pydantic is a Python library to perform data validation.
-接着你用一些值来创建这个类的实例,这些值会被校验,并被转换为适当的类型(在需要的情况下),返回一个包含所有数据的对象。
+You declare the "shape" of the data as classes with attributes.
-然后,你将获得这个对象的所有编辑器支持。
+And each attribute has a type.
-下面的例子来自 Pydantic 官方文档:
+Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.
-```Python
-{!../../../docs_src/python_types/tutorial010.py!}
-```
+And you get all the editor support with that resulting object.
+
+An example from the official Pydantic docs:
+
+=== "Python 3.10+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011.py!}
+ ```
!!! info
- 想进一步了解 Pydantic,请阅读其文档.
+ To learn more about Pydantic, check its docs.
+
+**FastAPI** is all based on Pydantic.
+
+You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+
+!!! tip
+ Pydantic has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields.
+
+## Type Hints with Metadata Annotations
+
+Python also has a feature that allows putting **additional metadata** in these type hints using `Annotated`.
+
+=== "Python 3.9+"
+
+ In Python 3.9, `Annotated` is part of the standard library, so you can import it from `typing`.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ In versions below Python 3.9, you import `Annotated` from `typing_extensions`.
+
+ It will already be installed with **FastAPI**.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013.py!}
+ ```
+
+Python itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`.
+
+But you can use this space in `Annotated` to provide **FastAPI** with additional metadata about how you want your application to behave.
+
+The important thing to remember is that ***the first ***type parameter****** you pass to `Annotated` is the **actual type**. The rest, is just metadata for other tools.
+
+For now, you just need to know that `Annotated` exists, and that it's standard Python. 😎
+
+Later you will see how **powerful** it can be.
-整个 **FastAPI** 建立在 Pydantic 的基础之上。
+!!! tip
+ The fact that this is **standard Python** means that you will still get the **best possible developer experience** in your editor, with the tools you use to analyze and refactor your code, etc. ✨
-实际上你将在 [教程 - 用户指南](tutorial/index.md){.internal-link target=_blank} 看到很多这种情况。
+ And also that your code will be very compatible with many other Python tools and libraries. 🚀
-## **FastAPI** 中的类型提示
+## Type hints in **FastAPI**
-**FastAPI** 利用这些类型提示来做下面几件事。
+**FastAPI** takes advantage of these type hints to do several things.
-使用 **FastAPI** 时用类型提示声明参数可以获得:
+With **FastAPI** you declare parameters with type hints and you get:
-* **编辑器支持**。
-* **类型检查**。
+* **Editor support**.
+* **Type checks**.
-...并且 **FastAPI** 还会用这些类型声明来:
+...and **FastAPI** uses the same declarations to:
-* **定义参数要求**:声明对请求路径参数、查询参数、请求头、请求体、依赖等的要求。
-* **转换数据**:将来自请求的数据转换为需要的类型。
-* **校验数据**: 对于每一个请求:
- * 当数据校验失败时自动生成**错误信息**返回给客户端。
-* 使用 OpenAPI **记录** API:
- * 然后用于自动生成交互式文档的用户界面。
+* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.
+* **Convert data**: from the request to the required type.
+* **Validate data**: coming from each request:
+ * Generating **automatic errors** returned to the client when the data is invalid.
+* **Document** the API using OpenAPI:
+ * which is then used by the automatic interactive documentation user interfaces.
-听上去有点抽象。不过不用担心。你将在 [教程 - 用户指南](tutorial/index.md){.internal-link target=_blank} 中看到所有的实战。
+This might all sound abstract. Don't worry. You'll see all this in action in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
-最重要的是,通过使用标准的 Python 类型,只需要在一个地方声明(而不是添加更多的类、装饰器等),**FastAPI** 会为你完成很多的工作。
+The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
!!! info
- 如果你已经阅读了所有教程,回过头来想了解有关类型的更多信息,来自 `mypy` 的"速查表"是不错的资源。
+ If you already went through all the tutorial and came back to see more about types, a good resource is the "cheat sheet" from `mypy`.
diff --git a/docs/zh/docs/tutorial/background-tasks.md b/docs/zh/docs/tutorial/background-tasks.md
new file mode 100644
index 0000000000000..1782971922ab2
--- /dev/null
+++ b/docs/zh/docs/tutorial/background-tasks.md
@@ -0,0 +1,126 @@
+# Background Tasks
+
+You can define background tasks to be run *after* returning a response.
+
+This is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving the response.
+
+This includes, for example:
+
+* Email notifications sent after performing an action:
+ * As connecting to an email server and sending an email tends to be "slow" (several seconds), you can return the response right away and send the email notification in the background.
+* Processing data:
+ * For example, let's say you receive a file that must go through a slow process, you can return a response of "Accepted" (HTTP 202) and process it in the background.
+
+## Using `BackgroundTasks`
+
+First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:
+
+```Python hl_lines="1 13"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.
+
+## Create a task function
+
+Create a function to be run as the background task.
+
+It is just a standard function that can receive parameters.
+
+It can be an `async def` or normal `def` function, **FastAPI** will know how to handle it correctly.
+
+In this case, the task function will write to a file (simulating sending an email).
+
+And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
+
+```Python hl_lines="6-9"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+## Add the background task
+
+Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`:
+
+```Python hl_lines="14"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+`.add_task()` receives as arguments:
+
+* A task function to be run in the background (`write_notification`).
+* Any sequence of arguments that should be passed to the task function in order (`email`).
+* Any keyword arguments that should be passed to the task function (`message="some notification"`).
+
+## Dependency Injection
+
+Using `BackgroundTasks` also works with the dependency injection system, you can declare a parameter of type `BackgroundTasks` at multiple levels: in a *path operation function*, in a dependency (dependable), in a sub-dependency, etc.
+
+**FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="14 16 23 26"
+ {!> ../../../docs_src/background_tasks/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11 13 20 23"
+ {!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002.py!}
+ ```
+
+In this example, the messages will be written to the `log.txt` file *after* the response is sent.
+
+If there was a query in the request, it will be written to the log in a background task.
+
+And then another background task generated at the *path operation function* will write a message using the `email` path parameter.
+
+## Technical Details
+
+The class `BackgroundTasks` comes directly from `starlette.background`.
+
+It is imported/included directly into FastAPI so that you can import it from `fastapi` and avoid accidentally importing the alternative `BackgroundTask` (without the `s` at the end) from `starlette.background`.
+
+By only using `BackgroundTasks` (and not `BackgroundTask`), it's then possible to use it as a *path operation function* parameter and have **FastAPI** handle the rest for you, just like when using the `Request` object directly.
+
+It's still possible to use `BackgroundTask` alone in FastAPI, but you have to create the object in your code and return a Starlette `Response` including it.
+
+You can see more details in Starlette's official docs for Background Tasks.
+
+## Caveat
+
+If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like Celery.
+
+They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
+
+To see an example, check the [Project Generators](../project-generation.md){.internal-link target=_blank}, they all include Celery already configured.
+
+But if you need to access variables and objects from the same **FastAPI** app, or you need to perform small background tasks (like sending an email notification), you can simply just use `BackgroundTasks`.
+
+## Recap
+
+Import and use `BackgroundTasks` with parameters in *path operation functions* and dependencies to add background tasks.
diff --git a/docs/zh/docs/tutorial/bigger-applications.md b/docs/zh/docs/tutorial/bigger-applications.md
index 9f0134f683c9e..0defc84810e53 100644
--- a/docs/zh/docs/tutorial/bigger-applications.md
+++ b/docs/zh/docs/tutorial/bigger-applications.md
@@ -4,7 +4,7 @@
**FastAPI** 提供了一个方便的工具,可以在保持所有灵活性的同时构建你的应用程序。
-!!! info
+!!! !!! info
如果你来自 Flask,那这将相当于 Flask 的 Blueprints。
## 一个文件结构示例
@@ -26,19 +26,19 @@
│ └── admin.py
```
-!!! tip
+!!! !!! tip
上面有几个 `__init__.py` 文件:每个目录或子目录中都有一个。
这就是能将代码从一个文件导入到另一个文件的原因。
-
+
例如,在 `app/main.py` 中,你可以有如下一行:
```
from app.routers import items
```
-* `app` 目录包含了所有内容。并且它有一个空文件 `app/__init__.py`,因此它是一个「Python 包」(「Python 模块」的集合):`app`。
-* 它包含一个 `app/main.py` 文件。由于它位于一个 Python 包(一个包含 `__init__.py` 文件的目录)中,因此它是该包的一个「模块」:`app.main`。
+* `app` 目录包含了所有内容。 并且它有一个空文件 `app/__init__.py`,因此它是一个「Python 包」(「Python 模块」的集合):`app`。
+* 它包含一个 `app/main.py` 文件。 由于它位于一个 Python 包(一个包含 `__init__.py` 文件的目录)中,因此它是该包的一个「模块」:`app.main`。
* 还有一个 `app/dependencies.py` 文件,就像 `app/main.py` 一样,它是一个「模块」:`app.dependencies`。
* 有一个子目录 `app/routers/` 包含另一个 `__init__.py` 文件,因此它是一个「Python 子包」:`app.routers`。
* 文件 `app/routers/items.py` 位于 `app/routers/` 包中,因此它是一个子模块:`app.routers.items`。
@@ -46,23 +46,23 @@
* 还有一个子目录 `app/internal/` 包含另一个 `__init__.py` 文件,因此它是又一个「Python 子包」:`app.internal`。
* `app/internal/admin.py` 是另一个子模块:`app.internal.admin`。
-
+
## 多次使用不同的 `prefix` 包含同一个路由器
diff --git a/docs/zh/docs/tutorial/body-fields.md b/docs/zh/docs/tutorial/body-fields.md
index 053cae71c7c6f..da96baaecfbc0 100644
--- a/docs/zh/docs/tutorial/body-fields.md
+++ b/docs/zh/docs/tutorial/body-fields.md
@@ -1,4 +1,4 @@
-# 请求体 - 字段
+# Body - Fields
与使用 `Query`、`Path` 和 `Body` 在*路径操作函数*中声明额外的校验和元数据的方式相同,你可以使用 Pydantic 的 `Field` 在 Pydantic 模型内部声明校验和元数据。
@@ -6,42 +6,118 @@
首先,你必须导入它:
-```Python hl_lines="2"
-{!../../../docs_src/body_fields/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4"
+ !!! note "技术细节"
+ 实际上,Query、Path 和其他你将在之后看到的类,创建的是由一个共同的 Params 类派生的子类的对象,该共同类本身又是 Pydantic 的 FieldInfo 类的子类。
+ ```
+、Path 和其他你将在之后看到的类,创建的是由一个共同的 Params 类派生的子类的对象,该共同类本身又是 Pydantic 的 FieldInfo 类的子类。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2"
+ {!../../../docs_src/body_fields/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4"
+ !!! tip
+ 注意每个模型属性如何使用类型、默认值和 Field 在代码结构上和路径操作函数的参数是相同的,区别是用 Field 替换Path、Query 和 Body。
+ ```
+ 在代码结构上和*路径操作函数*的参数是相同的,区别是用 Field 替换Path、Query 和 Body。
+
!!! warning
- 注意,`Field` 是直接从 `pydantic` 导入的,而不是像其他的(`Query`,`Path`,`Body` 等)都从 `fastapi` 导入。
+ Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).
## 声明模型属性
然后,你可以对模型属性使用 `Field`:
-```Python hl_lines="9-10"
-{!../../../docs_src/body_fields/tutorial001.py!}
-```
+=== "Python 3.10+"
-`Field` 的工作方式和 `Query`、`Path` 和 `Body` 相同,包括它们的参数等等也完全相同。
+ ```Python hl_lines="11-14"
+ 总结
+ ```
-!!! note "技术细节"
- 实际上,`Query`、`Path` 和其他你将在之后看到的类,创建的是由一个共同的 `Params` 类派生的子类的对象,该共同类本身又是 Pydantic 的 `FieldInfo` 类的子类。
+=== "Python 3.9+"
- Pydantic 的 `Field` 也会返回一个 `FieldInfo` 的实例。
+ ```Python hl_lines="11-14"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
+ ```
- `Body` 也直接返回 `FieldInfo` 的一个子类的对象。还有其他一些你之后会看到的类是 `Body` 类的子类。
+=== "Python 3.6+"
+ ```Python hl_lines="12-15"
+ 请求体 - 字段
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9-12"
+ {!../../../docs_src/body_fields/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11-14"
+ !!! warning
+ 注意,Field 是直接从 pydantic 导入的,而不是像其他的(Query,Path,Body 等)都从 fastapi 导入。
+ ```
+ 是直接从 pydantic 导入的,而不是像其他的(Query,Path,Body 等)都从 fastapi 导入。
+
+
+`Field` 的工作方式和 `Query`、`Path` 和 `Body` 相同,包括它们的参数等等也完全相同。
+
+!!! note "Technical Details"
+ Actually, `Query`, `Path` and others you'll see next create objects of subclasses of a common `Param` class, which is itself a subclass of Pydantic's `FieldInfo` class.
+
+ Pydantic 的 `Field` 也会返回一个 `FieldInfo` 的实例。
+
+ `Body` 也直接返回 `FieldInfo` 的一个子类的对象。 还有其他一些你之后会看到的类是 `Body` 类的子类。
+
请记住当你从 `fastapi` 导入 `Query`、`Path` 等对象时,他们实际上是返回特殊类的函数。
!!! tip
- 注意每个模型属性如何使用类型、默认值和 `Field` 在代码结构上和*路径操作函数*的参数是相同的,区别是用 `Field` 替换`Path`、`Query` 和 `Body`。
+ Notice how each model's attribute with a type, default value and `Field` has the same structure as a *path operation function's* parameter, with `Field` instead of `Path`, `Query` and `Body`.
## 添加额外信息
-你可以在 `Field`、`Query`、`Body` 中声明额外的信息。这些信息将包含在生成的 JSON Schema 中。
+你可以在 `Field`、`Query`、`Body` 中声明额外的信息。 这些信息将包含在生成的 JSON Schema 中。
你将在文档的后面部分学习声明示例时,了解到更多有关添加额外信息的知识。
-## 总结
+!!! warning
+ Extra keys passed to `Field` will also be present in the resulting OpenAPI schema for your application. As these keys may not necessarily be part of the OpenAPI specification, some OpenAPI tools, for example [the OpenAPI validator](https://validator.swagger.io/), may not work with your generated schema.
+
+## Recap
你可以使用 Pydantic 的 `Field` 为模型属性声明额外的校验和元数据。
diff --git a/docs/zh/docs/tutorial/body-multiple-params.md b/docs/zh/docs/tutorial/body-multiple-params.md
index 34fa5b638ff1d..6219c9aca93f2 100644
--- a/docs/zh/docs/tutorial/body-multiple-params.md
+++ b/docs/zh/docs/tutorial/body-multiple-params.md
@@ -8,12 +8,44 @@
你还可以通过将默认值设置为 `None` 来将请求体参数声明为可选参数:
-```Python hl_lines="17-19"
-{!../../../docs_src/body_multiple_params/tutorial001.py!}
-```
+=== "Python 3.10+"
-!!! note
- 请注意,在这种情况下,将从请求体获取的 `item` 是可选的。因为它的默认值为 `None`。
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="17-19"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001.py!}
+ ```
+
+!!! !!! note
+ 请注意,在这种情况下,将从请求体获取的 `item` 是可选的。 因为它的默认值为 `None`。
## 多个请求体参数
@@ -30,11 +62,19 @@
但是你也可以声明多个请求体参数,例如 `item` 和 `user`:
-```Python hl_lines="20"
-{!../../../docs_src/body_multiple_params/tutorial002.py!}
-```
+=== "Python 3.10+"
-在这种情况下,**FastAPI** 将注意到该函数中有多个请求体参数(两个 Pydantic 模型参数)。
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="22"
+ {!../../../docs_src/body_multiple_params/tutorial002.py!}
+ ```
+
+如果你就按原样声明它,因为它是一个单一值,**FastAPI** 将假定它是一个查询参数。
因此,它将使用参数名称作为请求体中的键(字段名称),并期望一个类似于以下内容的请求体:
@@ -54,7 +94,7 @@
```
!!! note
- 请注意,即使 `item` 的声明方式与之前相同,但现在它被期望通过 `item` 键内嵌在请求体中。
+ Notice that even though the `item` was declared the same way as before, it is now expected to be inside of the body with a key `item`.
**FastAPI** 将自动对请求中的数据进行转换,因此 `item` 参数将接收指定的内容,`user` 参数也是如此。
@@ -67,17 +107,50 @@
例如,为了扩展先前的模型,你可能决定除了 `item` 和 `user` 之外,还想在同一请求体中具有另一个键 `importance`。
-如果你就按原样声明它,因为它是一个单一值,**FastAPI** 将假定它是一个查询参数。
+在这种情况下,**FastAPI** 将注意到该函数中有多个请求体参数(两个 Pydantic 模型参数)。
但是你可以使用 `Body` 指示 **FastAPI** 将其作为请求体的另一个键进行处理。
+=== "Python 3.10+"
-```Python hl_lines="22"
-{!../../../docs_src/body_multiple_params/tutorial003.py!}
-```
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
+ ```
-在这种情况下,**FastAPI** 将期望像这样的请求体:
+=== "Python 3.9+"
+
+ ```Python hl_lines="23"
+ !!! info
+ Body 同样具有与 Query、Path 以及其他后面将看到的类完全相同的额外校验和元数据参数。
+ ```
+ 同样具有与 Query、Path 以及其他后面将看到的类完全相同的额外校验和元数据参数。
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24"
+ {!../../../docs_src/body_multiple_params/tutorial003.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="20"
+ {!../../../docs_src/body_multiple_params/tutorial004.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="22"
+ {!../../../docs_src/body_multiple_params/tutorial005.py!}
+ ```
+
+在这种情况下,**FastAPI** 将期望像这样的请求体:
```JSON
{
@@ -103,19 +176,59 @@
由于默认情况下单一值被解释为查询参数,因此你不必显式地添加 `Query`,你可以仅执行以下操作:
+```Python
+!!! note
+ 请注意,即使 item 的声明方式与之前相同,但现在它被期望通过 item 键内嵌在请求体中。
+```
+ 的声明方式与之前相同,但现在它被期望通过 item 键内嵌在请求体中。
+
+
+Or in Python 3.10 and above:
+
```Python
q: str = None
```
比如:
-```Python hl_lines="25"
-{!../../../docs_src/body_multiple_params/tutorial004.py!}
-```
+=== "Python 3.10+"
-!!! info
- `Body` 同样具有与 `Query`、`Path` 以及其他后面将看到的类完全相同的额外校验和元数据参数。
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="28"
+ {!../../../docs_src/body_multiple_params/tutorial001.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="25"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004.py!}
+ ```
+
+!!! info
+ `Body` also has all the same extra validation and metadata parameters as `Query`,`Path` and others you will see later.
## 嵌入单个请求体参数
@@ -131,9 +244,41 @@ item: Item = Body(embed=True)
比如:
-```Python hl_lines="15"
-{!../../../docs_src/body_multiple_params/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="17"
+ 总结
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005.py!}
+ ```
在这种情况下,**FastAPI** 将期望像这样的请求体:
@@ -159,7 +304,7 @@ item: Item = Body(embed=True)
}
```
-## 总结
+## Recap
你可以添加多个请求体参数到*路径操作函数*中,即使一个请求只能有一个请求体。
diff --git a/docs/zh/docs/tutorial/body-nested-models.md b/docs/zh/docs/tutorial/body-nested-models.md
index 7649ee6feafed..7d4819642168f 100644
--- a/docs/zh/docs/tutorial/body-nested-models.md
+++ b/docs/zh/docs/tutorial/body-nested-models.md
@@ -4,13 +4,23 @@
## List 字段
-你可以将一个属性定义为拥有子元素的类型。例如 Python `list`:
+你可以将一个属性定义为拥有子元素的类型。 例如 Python `list`:
-```Python hl_lines="12"
-{!../../../docs_src/body_nested_models/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="14"
+ 除了普通的单一值类型(如 str、int、float 等)外,你还可以使用从 str 继承的更复杂的单一值类型。
+ ```
+、int、float 等)外,你还可以使用从 str 继承的更复杂的单一值类型。
+
-这将使 `tags` 成为一个由元素组成的列表。不过它没有声明每个元素的类型。
+这将使 `tags` 成为一个由元素组成的列表。 不过它没有声明每个元素的类型。
## 具有子类型的 List 字段
@@ -18,19 +28,29 @@
### 从 typing 导入 `List`
+In Python 3.9 and above you can use the standard `list` to declare these type annotations as we'll see below. 💡
+
首先,从 Python 的标准库 `typing` 模块中导入 `List`:
```Python hl_lines="1"
-{!../../../docs_src/body_nested_models/tutorial002.py!}
+{!../../../docs_src/body_nested_models/tutorial001.py!}
```
### 声明具有子类型的 List
要声明具有子类型的类型,例如 `list`、`dict`、`tuple`:
-* 从 `typing` 模块导入它们
+* If you are in a Python version lower than 3.9, import their equivalent version from the `typing` module
* 使用方括号 `[` 和 `]` 将子类型作为「类型参数」传入
+In Python 3.9 it would be:
+
+```Python
+my_list: list[str]
+```
+
+In versions of Python before 3.9, it would be:
+
```Python
from typing import List
@@ -43,9 +63,23 @@ my_list: List[str]
因此,在我们的示例中,我们可以将 `tags` 明确地指定为一个「字符串列表」:
-```Python hl_lines="14"
-{!../../../docs_src/body_nested_models/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!../../../docs_src/body_nested_models/tutorial002.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="14"
+ {!../../../docs_src/body_nested_models/tutorial002.py!}
+ ```
## Set 类型
@@ -55,9 +89,23 @@ Python 具有一种特殊的数据类型来保存一组唯一的元素,即 `se
然后我们可以导入 `Set` 并将 `tag` 声明为一个由 `str` 组成的 `set`:
-```Python hl_lines="1 14"
-{!../../../docs_src/body_nested_models/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!../../../docs_src/body_nested_models/tutorial009.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 14"
+ {!../../../docs_src/body_nested_models/tutorial003.py!}
+ ```
这样,即使你收到带有重复数据的请求,这些数据也会被转换为一组唯一项。
@@ -73,23 +121,53 @@ Pydantic 模型的每个属性都具有类型。
因此,你可以声明拥有特定属性名称、类型和校验的深度嵌套的 JSON 对象。
-上述这些都可以任意的嵌套。
+All that, arbitrarily nested.
### 定义子模型
例如,我们可以定义一个 `Image` 模型:
-```Python hl_lines="9 10 11"
-{!../../../docs_src/body_nested_models/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7-9"
+ {!../../../docs_src/body_nested_models/tutorial004.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9-11"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-11"
+ {!../../../docs_src/body_nested_models/tutorial004.py!}
+ ```
### 将子模型用作类型
然后我们可以将其用作一个属性的类型:
-```Python hl_lines="20"
-{!../../../docs_src/body_nested_models/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18"
+ 例如:
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ 从 typing 模块导入它们
+ ```
+ 模块导入它们
+
这意味着 **FastAPI** 将期望类似于以下内容的请求体:
@@ -116,15 +194,32 @@ Pydantic 模型的每个属性都具有类型。
## 特殊的类型和校验
-除了普通的单一值类型(如 `str`、`int`、`float` 等)外,你还可以使用从 `str` 继承的更复杂的单一值类型。
+Apart from normal singular types like `str`, `int`, `float`, etc. You can use more complex singular types that inherit from `str`.
-要了解所有的可用选项,请查看关于 来自 Pydantic 的外部类型 的文档。你将在下一章节中看到一些示例。
+要了解所有的可用选项,请查看关于 来自 Pydantic 的外部类型 的文档。 你将在下一章节中看到一些示例。
例如,在 `Image` 模型中我们有一个 `url` 字段,我们可以把它声明为 Pydantic 的 `HttpUrl`,而不是 `str`:
-```Python hl_lines="4 10"
-{!../../../docs_src/body_nested_models/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="2 8"
+ {!../../../docs_src/body_nested_models/tutorial005.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4 10"
+ !!! info
+ 请注意 images 键现在具有一组 image 对象是如何发生的。
+ ```
+ 键现在具有一组 image 对象是如何发生的。
+
该字符串将被检查是否为有效的 URL,并在 JSON Schema / OpenAPI 文档中进行记录。
@@ -132,9 +227,26 @@ Pydantic 模型的每个属性都具有类型。
你还可以将 Pydantic 模型用作 `list`、`set` 等的子类型:
-```Python hl_lines="20"
-{!../../../docs_src/body_nested_models/tutorial006.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18"
+ {!../../../docs_src/body_nested_models/tutorial006.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ !!! tip
+ 请记住 JSON 仅支持将 str 作为键。
+ ```
+ 作为键。
+
这将期望(转换,校验,记录文档等)下面这样的 JSON 请求体:
@@ -163,18 +275,32 @@ Pydantic 模型的每个属性都具有类型。
```
!!! info
- 请注意 `images` 键现在具有一组 image 对象是如何发生的。
+ Notice how the `images` key now has a list of image objects.
## 深度嵌套模型
你可以定义任意深度的嵌套模型:
-```Python hl_lines="9 14 20 23 27"
-{!../../../docs_src/body_nested_models/tutorial007.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 12 18 21 25"
+ 上述这些都可以任意的嵌套。
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9 14 20 23 27"
+ 总结
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 14 20 23 27"
+ {!../../../docs_src/body_nested_models/tutorial007.py!}
+ ```
!!! info
- 请注意 `Offer` 拥有一组 `Item` 而反过来 `Item` 又是一个可选的 `Image` 列表是如何发生的。
+ Notice how `Offer` has a list of `Item`s, which in turn have an optional list of `Image`s
## 纯列表请求体
@@ -184,19 +310,33 @@ Pydantic 模型的每个属性都具有类型。
images: List[Image]
```
-例如:
+or in Python 3.9 and above:
-```Python hl_lines="15"
-{!../../../docs_src/body_nested_models/tutorial008.py!}
+```Python
+images: list[Image]
```
+as in:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15"
+ {!../../../docs_src/body_nested_models/tutorial008.py!}
+ ```
+
## 无处不在的编辑器支持
你可以随处获得编辑器支持。
即使是列表中的元素:
-
+
如果你直接使用 `dict` 而不是 Pydantic 模型,那你将无法获得这种编辑器支持。
@@ -218,27 +358,38 @@ images: List[Image]
在下面的例子中,你将接受任意键为 `int` 类型并且值为 `float` 类型的 `dict`:
-```Python hl_lines="15"
-{!../../../docs_src/body_nested_models/tutorial009.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="7"
+ https://fastapi.tiangolo.com/img/tutorial/body-nested-models/image01.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ !!! info
+ 请注意 Offer 拥有一组 Item 而反过来 Item 又是一个可选的 Image 列表是如何发生的。
+ ```
+ 拥有一组 Item 而反过来 Item 又是一个可选的 Image 列表是如何发生的。
+
!!! tip
- 请记住 JSON 仅支持将 `str` 作为键。
+ Have in mind that JSON only supports `str` as keys.
但是 Pydantic 具有自动转换数据的功能。
-
+
这意味着,即使你的 API 客户端只能将字符串作为键发送,只要这些字符串内容仅包含整数,Pydantic 就会对其进行转换并校验。
-
+
然后你接收的名为 `weights` 的 `dict` 实际上将具有 `int` 类型的键和 `float` 类型的值。
-## 总结
+## Recap
使用 **FastAPI** 你可以拥有 Pydantic 模型提供的极高灵活性,同时保持代码的简单、简短和优雅。
而且还具有下列好处:
* 编辑器支持(处处皆可自动补全!)
-* 数据转换(也被称为解析/序列化)
+* Data conversion (a.k.a. parsing / serialization)
* 数据校验
* 模式文档
* 自动生成的文档
diff --git a/docs/zh/docs/tutorial/body-updates.md b/docs/zh/docs/tutorial/body-updates.md
index 43f20f8fcbd9c..e5a080eb6aafb 100644
--- a/docs/zh/docs/tutorial/body-updates.md
+++ b/docs/zh/docs/tutorial/body-updates.md
@@ -4,15 +4,29 @@
更新数据请用 HTTP `PUT` 操作。
-把输入数据转换为以 JSON 格式存储的数据(比如,使用 NoSQL 数据库时),可以使用 `jsonable_encoder`。例如,把 `datetime` 转换为 `str`。
+把输入数据转换为以 JSON 格式存储的数据(比如,使用 NoSQL 数据库时),可以使用 `jsonable_encoder`。 例如,把 `datetime` 转换为 `str`。
-```Python hl_lines="30-35"
-{!../../../docs_src/body_updates/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="28-33"
+ !!! note "笔记"
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="30-35"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="30-35"
+ {!../../../docs_src/body_updates/tutorial001.py!}
+ ```
`PUT` 用于接收替换现有数据的数据。
-### 关于更新数据的警告
+### Warning about replacing
用 `PUT` 把数据项 `bar` 更新为以下内容时:
@@ -34,14 +48,13 @@
即,只发送要更新的数据,其余数据保持不变。
-!!! Note "笔记"
-
- `PATCH` 没有 `PUT` 知名,也怎么不常用。
+!!! Note
+ `PATCH` is less commonly used and known than `PUT`.
很多人甚至只用 `PUT` 实现部分更新。
-
+
**FastAPI** 对此没有任何限制,可以**随意**互换使用这两种操作。
-
+
但本指南也会分别介绍这两种操作各自的用途。
### 使用 Pydantic 的 `exclude_unset` 参数
@@ -54,9 +67,23 @@
然后再用它生成一个只含已设置(在请求中所发送)数据,且省略了默认值的 `dict`:
-```Python hl_lines="34"
-{!../../../docs_src/body_updates/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="32"
+ 关于更新数据的警告
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="34"
+ {!> ../../../docs_src/body_updates/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="34"
+ {!../../../docs_src/body_updates/tutorial002.py!}
+ ```
### 使用 Pydantic 的 `update` 参数
@@ -64,9 +91,23 @@
例如,`stored_item_model.copy(update=update_data)`:
-```Python hl_lines="35"
-{!../../../docs_src/body_updates/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="33"
+ !!! Note "笔记"
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="35"
+ {!> ../../../docs_src/body_updates/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="35"
+ {!../../../docs_src/body_updates/tutorial002.py!}
+ ```
### 更新部分数据小结
@@ -83,19 +124,30 @@
* 把数据保存至数据库;
* 返回更新后的模型。
-```Python hl_lines="30-37"
-{!../../../docs_src/body_updates/tutorial002.py!}
-```
+=== "Python 3.10+"
-!!! tip "提示"
+ ```Python hl_lines="28-35"
+ {!> ../../../docs_src/body_updates/tutorial002_py310.py!}
+ ```
- 实际上,HTTP `PUT` 也可以完成相同的操作。
- 但本节以 `PATCH` 为例的原因是,该操作就是为了这种用例创建的。
+=== "Python 3.9+"
-!!! note "笔记"
+ ```Python hl_lines="30-37"
+ {!> ../../../docs_src/body_updates/tutorial002_py39.py!}
+ ```
- 注意,输入模型仍需验证。
+=== "Python 3.6+"
- 因此,如果希望接收的部分更新数据可以省略其他所有属性,则要把模型中所有的属性标记为可选(使用默认值或 `None`)。
+ ```Python hl_lines="30-37"
+ {!../../../docs_src/body_updates/tutorial002.py!}
+ ```
+!!! 实际上,HTTP `PUT` 也可以完成相同的操作。
+
+ 但本节以 `PATCH` 为例的原因是,该操作就是为了这种用例创建的。
+
+!!! 注意,输入模型仍需验证。
+
+ 因此,如果希望接收的部分更新数据可以省略其他所有属性,则要把模型中所有的属性标记为可选(使用默认值或 `None`)。
+
为了区分用于**更新**所有可选值的模型与用于**创建**包含必选值的模型,请参照[更多模型](extra-models.md){.internal-link target=_blank} 一节中的思路。
diff --git a/docs/zh/docs/tutorial/body.md b/docs/zh/docs/tutorial/body.md
index f80ab5bf59069..7d840d8ade353 100644
--- a/docs/zh/docs/tutorial/body.md
+++ b/docs/zh/docs/tutorial/body.md
@@ -2,24 +2,33 @@
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。
-**请求**体是客户端发送给 API 的数据。**响应**体是 API 发送给客户端的数据。
+**请求**体是客户端发送给 API 的数据。 **响应**体是 API 发送给客户端的数据。
-你的 API 几乎总是要发送**响应**体。但是客户端并不总是需要发送**请求**体。
+你的 API 几乎总是要发送**响应**体。 但是客户端并不总是需要发送**请求**体。
我们使用 Pydantic 模型来声明**请求**体,并能够获得它们所具有的所有能力和优点。
-!!! info
- 你不能使用 `GET` 操作(HTTP 方法)发送请求体。
+!!! 要发送数据,你必须使用下列方法之一:`POST`(较常见)、`PUT`、`DELETE` 或 `PATCH`。
- 要发送数据,你必须使用下列方法之一:`POST`(较常见)、`PUT`、`DELETE` 或 `PATCH`。
+ Sending a body with a `GET` request has an undefined behavior in the specifications, nevertheless, it is supported by FastAPI, only for very complex/extreme use cases.
+
+ As it is discouraged, the interactive docs with Swagger UI won't show the documentation for the body when using `GET`, and proxies in the middle might not support it.
## 导入 Pydantic 的 `BaseModel`
首先,你需要从 `pydantic` 中导入 `BaseModel`:
-```Python hl_lines="2"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="2"
+ https://fastapi.tiangolo.com/img/tutorial/body/image03.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4"
+ {!../../../docs_src/body/tutorial001.py!}
+ ```
## 创建数据模型
@@ -27,11 +36,22 @@
使用标准的 Python 类型来声明所有属性:
-```Python hl_lines="5-9"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="5-9"
+ !!! info
+ 你不能使用 GET 操作(HTTP 方法)发送请求体。
+ ```
+ 操作(HTTP 方法)发送请求体。
+
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="7-11"
+ {!../../../docs_src/body/tutorial001.py!}
+ ```
-和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。否则它是一个必需属性。将默认值设为 `None` 可使其成为可选属性。
+和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。 否则它是一个必需属性。 将默认值设为 `None` 可使其成为可选属性。
例如,上面的模型声明了一个这样的 JSON「`object`」(或 Python `dict`):
@@ -57,9 +77,17 @@
使用与声明路径和查询参数的相同方式声明请求体,即可将其添加到「路径操作」中:
-```Python hl_lines="16"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="16"
+ https://fastapi.tiangolo.com/img/tutorial/body/image05.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18"
+ {!../../../docs_src/body/tutorial001.py!}
+ ```
...并且将它的类型声明为你创建的 `Item` 模型。
@@ -80,21 +108,21 @@
你所定义模型的 JSON 模式将成为生成的 OpenAPI 模式的一部分,并且在交互式 API 文档中展示:
-
+
而且还将在每一个需要它们的*路径操作*的 API 文档中使用:
-
+
## 编辑器支持
在你的编辑器中,你会在函数内部的任意地方得到类型提示和代码补全(如果你接收的是一个 `dict` 而不是 Pydantic 模型,则不会发生这种情况):
-
+
你还会获得对不正确的类型操作的错误检查:
-
+
这并非偶然,整个框架都是围绕该设计而构建。
@@ -106,15 +134,34 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
但是在 PyCharm 和绝大多数其他 Python 编辑器中你也会获得同样的编辑器支持:
-
+
+
+!!! tip
+ If you use PyCharm as your editor, you can use the Pydantic PyCharm Plugin.
+
+ It improves editor support for Pydantic models, with:
+
+ * auto-completion
+ * type checks
+ * refactoring
+ * searching
+ * inspections
## 使用模型
在函数内部,你可以直接访问模型对象的所有属性:
-```Python hl_lines="19"
-{!../../../docs_src/body/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="19"
+ https://fastapi.tiangolo.com/img/tutorial/body/image01.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="21"
+ {!../../../docs_src/body/tutorial002.py!}
+ ```
## 请求体 + 路径参数
@@ -122,9 +169,17 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
**FastAPI** 将识别出与路径参数匹配的函数参数应**从路径中获取**,而声明为 Pydantic 模型的函数参数应**从请求体中获取**。
-```Python hl_lines="15-16"
-{!../../../docs_src/body/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="15-16"
+ https://fastapi.tiangolo.com/img/tutorial/body/image04.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="17-18"
+ {!../../../docs_src/body/tutorial003.py!}
+ ```
## 请求体 + 路径参数 + 查询参数
@@ -132,9 +187,17 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
**FastAPI** 会识别它们中的每一个,并从正确的位置获取数据。
-```Python hl_lines="16"
-{!../../../docs_src/body/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="16"
+ https://fastapi.tiangolo.com/img/tutorial/body/image02.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18"
+ {!../../../docs_src/body/tutorial004.py!}
+ ```
函数参数将依次按如下规则进行识别:
@@ -142,6 +205,11 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
* 如果参数属于**单一类型**(比如 `int`、`float`、`str`、`bool` 等)它将被解释为**查询**参数。
* 如果参数的类型被声明为一个 **Pydantic 模型**,它将被解释为**请求体**。
+!!! note
+ FastAPI will know that the value of `q` is not required because of the default value `= None`.
+
+ The `Union` in `Union[str, None]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
+
## 不使用 Pydantic
-如果你不想使用 Pydantic 模型,你还可以使用 **Body** 参数。请参阅文档 [请求体 - 多个参数:请求体中的单一值](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}。
+如果你不想使用 Pydantic 模型,你还可以使用 **Body** 参数。 请参阅文档 [请求体 - 多个参数:请求体中的单一值](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}。
diff --git a/docs/zh/docs/tutorial/cookie-params.md b/docs/zh/docs/tutorial/cookie-params.md
index d67daf0f9051e..5e9a59af732f5 100644
--- a/docs/zh/docs/tutorial/cookie-params.md
+++ b/docs/zh/docs/tutorial/cookie-params.md
@@ -6,9 +6,44 @@
首先,导入 `Cookie`:
-```Python hl_lines="3"
-{!../../../docs_src/cookie_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ !!! info
+ 你需要使用 Cookie 来声明 cookie 参数,否则参数将会被解释为查询参数。
+ ```
+ 来声明 cookie 参数,否则参数将会被解释为查询参数。
+
## 声明 `Cookie` 参数
@@ -16,19 +51,53 @@
第一个值是参数的默认值,同时也可以传递所有验证参数或注释参数,来校验参数:
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ 总结
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
-```Python hl_lines="9"
-{!../../../docs_src/cookie_params/tutorial001.py!}
-```
+ ```Python hl_lines="9"
+ !!! note "技术细节"
+ Cookie 、Path 、Query是兄弟类,它们都继承自公共的 Param 类
+ ```
+ 、Path 、Query是兄弟类,它们都继承自公共的 Param 类
+
-!!! note "技术细节"
- `Cookie` 、`Path` 、`Query`是兄弟类,它们都继承自公共的 `Param` 类
+!!! note "Technical Details"
+ `Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class.
但请记住,当你从 `fastapi` 导入的 `Query`、`Path`、`Cookie` 或其他参数声明函数,这些实际上是返回特殊类的函数。
!!! info
- 你需要使用 `Cookie` 来声明 cookie 参数,否则参数将会被解释为查询参数。
+ To declare cookies, you need to use `Cookie`, because otherwise the parameters would be interpreted as query parameters.
-## 总结
+## Recap
使用 `Cookie` 声明 cookie 参数,使用方式与 `Query` 和 `Path` 类似。
diff --git a/docs/zh/docs/tutorial/cors.md b/docs/zh/docs/tutorial/cors.md
index ddd4e76825366..171989cf1da18 100644
--- a/docs/zh/docs/tutorial/cors.md
+++ b/docs/zh/docs/tutorial/cors.md
@@ -24,7 +24,7 @@
在这种情况下,它必须包含 `http://localhost:8080`,前端才能正常工作。
-## 通配符
+## Wildcards
也可以使用 `"*"`(一个「通配符」)声明这个列表,表示全部都是允许的。
@@ -54,13 +54,13 @@
支持以下参数:
-* `allow_origins` - 一个允许跨域请求的源列表。例如 `['https://example.org', 'https://www.example.org']`。你可以使用 `['*']` 允许任何源。
-* `allow_origin_regex` - 一个正则表达式字符串,匹配的源允许跨域请求。例如 `'https://.*\.example\.org'`。
-* `allow_methods` - 一个允许跨域请求的 HTTP 方法列表。默认为 `['GET']`。你可以使用 `['*']` 来允许所有标准方法。
-* `allow_headers` - 一个允许跨域请求的 HTTP 请求头列表。默认为 `[]`。你可以使用 `['*']` 允许所有的请求头。`Accept`、`Accept-Language`、`Content-Language` 以及 `Content-Type` 请求头总是允许 CORS 请求。
-* `allow_credentials` - 指示跨域请求支持 cookies。默认是 `False`。另外,允许凭证时 `allow_origins` 不能设定为 `['*']`,必须指定源。
-* `expose_headers` - 指示可以被浏览器访问的响应头。默认为 `[]`。
-* `max_age` - 设定浏览器缓存 CORS 响应的最长时间,单位是秒。默认为 `600`。
+* `allow_origins` - 一个允许跨域请求的源列表。 E.g. 例如 `['https://example.org', 'https://www.example.org']`。 你可以使用 `['*']` 允许任何源。
+* `allow_origin_regex` - 一个正则表达式字符串,匹配的源允许跨域请求。 例如 `'https://.*\.example\.org'`。
+* `allow_methods` - 一个允许跨域请求的 HTTP 方法列表。 默认为 `['GET']`。 你可以使用 `['*']` 来允许所有标准方法。
+* `allow_headers` - 一个允许跨域请求的 HTTP 请求头列表。 默认为 `[]`。 你可以使用 `['*']` 允许所有的请求头。 `Accept`、`Accept-Language`、`Content-Language` 以及 `Content-Type` 请求头总是允许 CORS 请求。
+* `allow_credentials` - 指示跨域请求支持 cookies。 默认是 `False`。 另外,允许凭证时 `allow_origins` 不能设定为 `['*']`,必须指定源。
+* `expose_headers` - 指示可以被浏览器访问的响应头。 默认为 `[]`。
+* `max_age` - 设定浏览器缓存 CORS 响应的最长时间,单位是秒。 默认为 `600`。
中间件响应两种特定类型的 HTTP 请求……
@@ -72,13 +72,13 @@
### 简单请求
-任何带有 `Origin` 请求头的请求。在这种情况下,中间件将像平常一样传递请求,但是在响应中包含适当的 CORS headers。
+任何带有 `Origin` 请求头的请求。 在这种情况下,中间件将像平常一样传递请求,但是在响应中包含适当的 CORS headers。
## 更多信息
更多关于 CORS 的信息,请查看 Mozilla CORS 文档。
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以使用 `from starlette.middleware.cors import CORSMiddleware`。
- 出于方便,**FastAPI** 在 `fastapi.middleware` 中为开发者提供了几个中间件。但是大多数可用的中间件都是直接来自 Starlette。
+ 出于方便,**FastAPI** 在 `fastapi.middleware` 中为开发者提供了几个中间件。 但是大多数可用的中间件都是直接来自 Starlette。
diff --git a/docs/zh/docs/tutorial/debugging.md b/docs/zh/docs/tutorial/debugging.md
index 51801d4984b9e..10a7a31a05296 100644
--- a/docs/zh/docs/tutorial/debugging.md
+++ b/docs/zh/docs/tutorial/debugging.md
@@ -1,4 +1,4 @@
-# 调试
+# Debugging
你可以在编辑器中连接调试器,例如使用 Visual Studio Code 或 PyCharm。
@@ -44,12 +44,14 @@ $ python myapp.py
那么文件中由 Python 自动创建的内部变量 `__name__`,会将字符串 `"__main__"` 作为值。
-所以,下面这部分代码才会运行:
+So, the section:
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
```
+will run.
+
---
如果你是导入这个模块(文件)就不会这样。
@@ -64,13 +66,15 @@ from myapp import app
在这种情况下,`myapp.py` 内部的自动变量不会有值为 `"__main__"` 的变量 `__name__`。
-所以,下面这一行不会被执行:
+So, the line:
```Python
uvicorn.run(app, host="0.0.0.0", port=8000)
```
-!!! info
+will not be executed.
+
+!!! !!! info
更多信息请检查 Python 官方文档.
## 使用你的调试器运行代码
@@ -81,7 +85,7 @@ from myapp import app
例如,你可以在 Visual Studio Code 中:
-* 进入到「调试」面板。
+* Go to the "Debug" panel.
* 「添加配置...」。
* 选中「Python」
* 运行「Python:当前文件(集成终端)」选项的调试器。
@@ -90,14 +94,14 @@ from myapp import app
看起来可能是这样:
-
+
---
如果使用 Pycharm,你可以:
* 打开「运行」菜单。
-* 选中「调试...」。
+* Select the option "Debug...".
* 然后出现一个上下文菜单。
* 选择要调试的文件(本例中的 `main.py`)。
@@ -105,4 +109,4 @@ from myapp import app
看起来可能是这样:
-
+
diff --git a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
index f404820df0119..7da62b650bca0 100644
--- a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -8,13 +8,37 @@
=== "Python 3.10+"
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="7"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
- ```Python hl_lines="9"
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
{!> ../../../docs_src/dependencies/tutorial001.py!}
```
@@ -30,7 +54,7 @@
但这并不是声明依赖项的唯一方法(尽管它可能是更常见的方法)。
-关键因素是依赖项应该是 "可调用对象"。
+The key factor is that a dependency should be a "callable".
Python 中的 "**可调用对象**" 是指任何 Python 可以像函数一样 "调用" 的对象。
@@ -46,7 +70,7 @@ something()
something(some_argument, some_keyword_argument="foo")
```
-这就是 "可调用对象"。
+then it is a "callable".
## 类作为依赖项
@@ -73,19 +97,43 @@ fluffy = Cat(name="Mr Fluffy")
实际上 FastAPI 检查的是它是一个 "可调用对象"(函数,类或其他任何类型)以及定义的参数。
-如果您在 **FastAPI** 中传递一个 "可调用对象" 作为依赖项,它将分析该 "可调用对象" 的参数,并以处理路径操作函数的参数的方式来处理它们。包括子依赖项。
+如果您在 **FastAPI** 中传递一个 "可调用对象" 作为依赖项,它将分析该 "可调用对象" 的参数,并以处理路径操作函数的参数的方式来处理它们。 包括子依赖项。
-这也适用于完全没有参数的可调用对象。这与不带参数的路径操作函数一样。
+这也适用于完全没有参数的可调用对象。 这与不带参数的路径操作函数一样。
所以,我们可以将上面的依赖项 "可依赖对象" `common_parameters` 更改为类 `CommonQueryParams`:
=== "Python 3.10+"
+ ```Python hl_lines="11-15"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11-15"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12-16"
+ {!> ../../../docs_src/dependencies/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="9-13"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002.py!}
@@ -95,11 +143,35 @@ fluffy = Cat(name="Mr Fluffy")
=== "Python 3.10+"
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/dependencies/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="10"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="12"
{!> ../../../docs_src/dependencies/tutorial002.py!}
@@ -109,11 +181,35 @@ fluffy = Cat(name="Mr Fluffy")
=== "Python 3.10+"
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/dependencies/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/dependencies/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="6"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001.py!}
@@ -135,30 +231,65 @@ fluffy = Cat(name="Mr Fluffy")
=== "Python 3.10+"
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/dependencies/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial002.py!}
```
-**FastAPI** 调用 `CommonQueryParams` 类。这将创建该类的一个 "实例",该实例将作为参数 `commons` 被传递给你的函数。
+**FastAPI** 调用 `CommonQueryParams` 类。 这将创建该类的一个 "实例",该实例将作为参数 `commons` 被传递给你的函数。
## 类型注解 vs `Depends`
注意,我们在上面的代码中编写了两次`CommonQueryParams`:
-```Python
-commons: CommonQueryParams = Depends(CommonQueryParams)
-```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons: CommonQueryParams = Depends(CommonQueryParams)
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ ... = Depends(CommonQueryParams)
+ ```
最后的 `CommonQueryParams`:
```Python
-... = Depends(CommonQueryParams)
+... Depends(CommonQueryParams)
```
...实际上是 **Fastapi** 用来知道依赖项是什么的。
@@ -169,27 +300,74 @@ FastAPI 将从依赖项中提取声明的参数,这才是 FastAPI 实际调用
在本例中,第一个 `CommonQueryParams` :
-```Python
-commons: CommonQueryParams ...
-```
+=== "Python 3.6+"
+
+ ```Python
+ 这就是 "可调用对象"。
+ ```
-...对于 **FastAPI** 没有任何特殊的意义。FastAPI 不会使用它进行数据转换、验证等 (因为对于这,它使用 `= Depends(CommonQueryParams)`)。
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons: CommonQueryParams ...
+ ```
+
+...对于 **FastAPI** 没有任何特殊的意义。 FastAPI 不会使用它进行数据转换、验证等 (因为对于这,它使用 `= Depends(CommonQueryParams)`)。
你实际上可以只这样编写:
-```Python
-commons = Depends(CommonQueryParams)
-```
+=== "Python 3.6+"
+
+ ```Python
+ !!! tip
+ 如果这看起来更加混乱而不是更加有帮助,那么请忽略它,你不需要它。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons = Depends(CommonQueryParams)
+ ```
..就像:
=== "Python 3.10+"
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/dependencies/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial003.py!}
@@ -197,15 +375,26 @@ commons = Depends(CommonQueryParams)
但是声明类型是被鼓励的,因为那样你的编辑器就会知道将传递什么作为参数 `commons` ,然后它可以帮助你完成代码,类型检查,等等:
-
+
## 快捷方式
但是您可以看到,我们在这里有一些代码重复了,编写了`CommonQueryParams`两次:
-```Python
-commons: CommonQueryParams = Depends(CommonQueryParams)
-```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons: CommonQueryParams = Depends(CommonQueryParams)
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+ ```
**FastAPI** 为这些情况提供了一个快捷方式,在这些情况下,依赖项 *明确地* 是一个类,**FastAPI** 将 "调用" 它来创建类本身的一个实例。
@@ -213,15 +402,37 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
不是写成这样:
-```Python
-commons: CommonQueryParams = Depends(CommonQueryParams)
-```
+=== "Python 3.6+"
+
+ ```Python
+ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons: CommonQueryParams = Depends(CommonQueryParams)
+ ```
...而是这样写:
-```Python
-commons: CommonQueryParams = Depends()
-```
+=== "Python 3.6+"
+
+ ```Python
+ 关键因素是依赖项应该是 "可调用对象"。
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ commons: CommonQueryParams = Depends()
+ ```
您声明依赖项作为参数的类型,并使用 `Depends()` 作为该函数的参数的 "默认" 值(在 `=` 之后),而在 `Depends()` 中没有任何参数,而不是在 `Depends(CommonQueryParams)` 编写完整的类。
@@ -229,11 +440,35 @@ commons: CommonQueryParams = Depends()
=== "Python 3.10+"
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/dependencies/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial004_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="19"
{!> ../../../docs_src/dependencies/tutorial004.py!}
@@ -242,6 +477,6 @@ commons: CommonQueryParams = Depends()
... **FastAPI** 会知道怎么处理。
!!! tip
- 如果这看起来更加混乱而不是更加有帮助,那么请忽略它,你不*需要*它。
+ If that seems more confusing than helpful, disregard it, you don't *need* it.
- 这只是一个快捷方式。因为 **FastAPI** 关心的是帮助您减少代码重复。
+ 这只是一个快捷方式。 因为 **FastAPI** 关心的是帮助您减少代码重复。
diff --git a/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index 61ea371e5453e..f7961ad050a95 100644
--- a/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -4,7 +4,7 @@
或者说,有些依赖项不返回值。
-但仍要执行或解析该依赖项。
+But you still need it to be executed/solved.
对于这种情况,不必在声明*路径操作函数*的参数时使用 `Depends`,而是可以在*路径操作装饰器*中添加一个由 `dependencies` 组成的 `list`。
@@ -14,23 +14,36 @@
该参数的值是由 `Depends()` 组成的 `list`:
-```Python hl_lines="17"
-{!../../../docs_src/dependencies/tutorial006.py!}
-```
+=== "Python 3.9+"
-路径操作装饰器依赖项(以下简称为**“路径装饰器依赖项”**)的执行或解析方式和普通依赖项一样,但就算这些依赖项会返回值,它们的值也不会传递给*路径操作函数*。
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
+ ```
-!!! tip "提示"
+=== "Python 3.6+"
- 有些编辑器会检查代码中没使用过的函数参数,并显示错误提示。
+ ```Python hl_lines="18"
+ !!! tip "提示"
+ ```
- 在*路径操作装饰器*中使用 `dependencies` 参数,可以确保在执行依赖项的同时,避免编辑器显示错误提示。
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="17"
+ {!../../../docs_src/dependencies/tutorial006.py!}
+ ```
- 使用路径装饰器依赖项还可以避免开发新人误会代码中包含无用的未使用参数。
+These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*.
-!!! info "说明"
+!!! 有些编辑器会检查代码中没使用过的函数参数,并显示错误提示。
- 本例中,使用的是自定义响应头 `X-Key` 和 `X-Token`。
+ 在*路径操作装饰器*中使用 `dependencies` 参数,可以确保在执行依赖项的同时,避免编辑器显示错误提示。
+
+ It might also help avoid confusion for new developers that see an unused parameter in your code and could think it's unnecessary.
+
+!!! 本例中,使用的是自定义响应头 `X-Key` 和 `X-Token`。
但实际开发中,尤其是在实现安全措施时,最好使用 FastAPI 内置的[安全工具](../security/index.md){.internal-link target=_blank}(详见下一章)。
@@ -42,27 +55,78 @@
路径装饰器依赖项可以声明请求的需求项(比如响应头)或其他子依赖项:
-```Python hl_lines="6 11"
-{!../../../docs_src/dependencies/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="8 13"
+ {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!}
+ ```
-### 触发异常
+=== "Python 3.6+"
+
+ ```Python hl_lines="7 12"
+ !!! info "说明"
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6 11"
+ {!../../../docs_src/dependencies/tutorial006.py!}
+ ```
+
+### Raise exceptions
路径装饰器依赖项与正常的依赖项一样,可以 `raise` 异常:
-```Python hl_lines="8 13"
-{!../../../docs_src/dependencies/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10 15"
+ 但仍要执行或解析该依赖项。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 14"
+ 无论路径装饰器依赖项是否返回值,路径操作都不会使用这些值。
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8 13"
+ {!../../../docs_src/dependencies/tutorial006.py!}
+ ```
### 返回值
-无论路径装饰器依赖项是否返回值,路径操作都不会使用这些值。
+And they can return values or not, the values won't be used.
因此,可以复用在其他位置使用过的、(能返回值的)普通依赖项,即使没有使用这个值,也会执行该依赖项:
-```Python hl_lines="9 14"
-{!../../../docs_src/dependencies/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="11 16"
+ 路径操作装饰器依赖项(以下简称为“路径装饰器依赖项”)的执行或解析方式和普通依赖项一样,但就算这些依赖项会返回值,它们的值也不会传递给路径操作函数。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10 15"
+ 触发异常
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9 14"
+ {!../../../docs_src/dependencies/tutorial006.py!}
+ ```
## 为一组路径操作定义依赖项
diff --git a/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md
new file mode 100644
index 0000000000000..c0883364aff4c
--- /dev/null
+++ b/docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -0,0 +1,252 @@
+# Dependencies with yield
+
+FastAPI supports dependencies that do some extra steps after finishing.
+
+To do this, use `yield` instead of `return`, and write the extra steps after.
+
+!!! tip
+ Make sure to use `yield` one single time.
+
+!!! note "Technical Details"
+ Any function that is valid to use with:
+
+ * `@contextlib.contextmanager` or
+ * `@contextlib.asynccontextmanager`
+
+ would be valid to use as a **FastAPI** dependency.
+
+ In fact, FastAPI uses those two decorators internally.
+
+## A database dependency with `yield`
+
+For example, you could use this to create a database session and close it after finishing.
+
+Only the code prior to and including the `yield` statement is executed before sending a response:
+
+```Python hl_lines="2-4"
+{!../../../docs_src/dependencies/tutorial007.py!}
+```
+
+The yielded value is what is injected into *path operations* and other dependencies:
+
+```Python hl_lines="4"
+{!../../../docs_src/dependencies/tutorial007.py!}
+```
+
+The code following the `yield` statement is executed after the response has been delivered:
+
+```Python hl_lines="5-6"
+{!../../../docs_src/dependencies/tutorial007.py!}
+```
+
+!!! tip
+ You can use `async` or normal functions.
+
+ **FastAPI** will do the right thing with each, the same as with normal dependencies.
+
+## A dependency with `yield` and `try`
+
+If you use a `try` block in a dependency with `yield`, you'll receive any exception that was thrown when using the dependency.
+
+For example, if some code at some point in the middle, in another dependency or in a *path operation*, made a database transaction "rollback" or create any other error, you will receive the exception in your dependency.
+
+So, you can look for that specific exception inside the dependency with `except SomeException`.
+
+In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not.
+
+```Python hl_lines="3 5"
+{!../../../docs_src/dependencies/tutorial007.py!}
+```
+
+## Sub-dependencies with `yield`
+
+You can have sub-dependencies and "trees" of sub-dependencies of any size and shape, and any or all of them can use `yield`.
+
+**FastAPI** will make sure that the "exit code" in each dependency with `yield` is run in the correct order.
+
+For example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="6 14 22"
+ {!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="5 13 21"
+ {!> ../../../docs_src/dependencies/tutorial008_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 12 20"
+ {!> ../../../docs_src/dependencies/tutorial008.py!}
+ ```
+
+And all of them can use `yield`.
+
+In this case `dependency_c`, to execute its exit code, needs the value from `dependency_b` (here named `dep_b`) to still be available.
+
+And, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-19 26-27"
+ {!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="17-18 25-26"
+ {!> ../../../docs_src/dependencies/tutorial008_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="16-17 24-25"
+ {!> ../../../docs_src/dependencies/tutorial008.py!}
+ ```
+
+The same way, you could have dependencies with `yield` and `return` mixed.
+
+And you could have a single dependency that requires several other dependencies with `yield`, etc.
+
+You can have any combinations of dependencies that you want.
+
+**FastAPI** will make sure everything is run in the correct order.
+
+!!! note "Technical Details"
+ This works thanks to Python's Context Managers.
+
+ **FastAPI** uses them internally to achieve this.
+
+## Dependencies with `yield` and `HTTPException`
+
+You saw that you can use dependencies with `yield` and have `try` blocks that catch exceptions.
+
+It might be tempting to raise an `HTTPException` or similar in the exit code, after the `yield`. But **it won't work**.
+
+The exit code in dependencies with `yield` is executed *after* the response is sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} will have already run. There's nothing catching exceptions thrown by your dependencies in the exit code (after the `yield`).
+
+So, if you raise an `HTTPException` after the `yield`, the default (or any custom) exception handler that catches `HTTPException`s and returns an HTTP 400 response won't be there to catch that exception anymore.
+
+This is what allows anything set in the dependency (e.g. a DB session) to, for example, be used by background tasks.
+
+Background tasks are run *after* the response has been sent. So there's no way to raise an `HTTPException` because there's not even a way to change the response that is *already sent*.
+
+But if a background task creates a DB error, at least you can rollback or cleanly close the session in the dependency with `yield`, and maybe log the error or report it to a remote tracking system.
+
+If you have some code that you know could raise an exception, do the most normal/"Pythonic" thing and add a `try` block in that section of the code.
+
+If you have custom exceptions that you would like to handle *before* returning the response and possibly modifying the response, maybe even raising an `HTTPException`, create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+
+!!! tip
+ You can still raise exceptions including `HTTPException` *before* the `yield`. But not after.
+
+The sequence of execution is more or less like this diagram. Time flows from top to bottom. And each column is one of the parts interacting or executing code.
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant handler as Exception handler
+participant dep as Dep with yield
+participant operation as Path Operation
+participant tasks as Background tasks
+
+ Note over client,tasks: Can raise exception for dependency, handled after response is sent
+ Note over client,operation: Can raise HTTPException and can change the response
+ client ->> dep: Start request
+ Note over dep: Run code up to yield
+ opt raise
+ dep -->> handler: Raise HTTPException
+ handler -->> client: HTTP error response
+ dep -->> dep: Raise other exception
+ end
+ dep ->> operation: Run dependency, e.g. DB session
+ opt raise
+ operation -->> dep: Raise HTTPException
+ dep -->> handler: Auto forward exception
+ handler -->> client: HTTP error response
+ operation -->> dep: Raise other exception
+ dep -->> handler: Auto forward exception
+ end
+ operation ->> client: Return response to client
+ Note over client,operation: Response is already sent, can't change it anymore
+ opt Tasks
+ operation -->> tasks: Send background tasks
+ end
+ opt Raise other exception
+ tasks -->> dep: Raise other exception
+ end
+ Note over dep: After yield
+ opt Handle other exception
+ dep -->> dep: Handle exception, can't change response. E.g. close DB session.
+ end
+```
+
+!!! info
+ Only **one response** will be sent to the client. It might be one of the error responses or it will be the response from the *path operation*.
+
+ After one of those responses is sent, no other response can be sent.
+
+!!! tip
+ This diagram shows `HTTPException`, but you could also raise any other exception for which you create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+
+ If you raise any exception, it will be passed to the dependencies with yield, including `HTTPException`, and then **again** to the exception handlers. If there's no exception handler for that exception, it will then be handled by the default internal `ServerErrorMiddleware`, returning a 500 HTTP status code, to let the client know that there was an error in the server.
+
+## Context Managers
+
+### What are "Context Managers"
+
+"Context Managers" are any of those Python objects that you can use in a `with` statement.
+
+For example, you can use `with` to read a file:
+
+```Python
+with open("./somefile.txt") as f:
+ contents = f.read()
+ print(contents)
+```
+
+Underneath, the `open("./somefile.txt")` creates an object that is a called a "Context Manager".
+
+When the `with` block finishes, it makes sure to close the file, even if there were exceptions.
+
+When you create a dependency with `yield`, **FastAPI** will internally convert it to a context manager, and combine it with some other related tools.
+
+### Using context managers in dependencies with `yield`
+
+!!! warning
+ This is, more or less, an "advanced" idea.
+
+ If you are just starting with **FastAPI** you might want to skip it for now.
+
+In Python, you can create Context Managers by creating a class with two methods: `__enter__()` and `__exit__()`.
+
+You can also use them inside of **FastAPI** dependencies with `yield` by using `with` or `async with` statements inside of the dependency function:
+
+```Python hl_lines="1-9 13"
+{!../../../docs_src/dependencies/tutorial010.py!}
+```
+
+!!! tip
+ Another way to create a context manager is with:
+
+ * `@contextlib.contextmanager` or
+ * `@contextlib.asynccontextmanager`
+
+ using them to decorate a function with a single `yield`.
+
+ That's what **FastAPI** uses internally for dependencies with `yield`.
+
+ But you don't have to use the decorators for FastAPI dependencies (and you shouldn't).
+
+ FastAPI will do it for you internally.
diff --git a/docs/zh/docs/tutorial/dependencies/global-dependencies.md b/docs/zh/docs/tutorial/dependencies/global-dependencies.md
index 3f7afa32cd1b3..33e768bbe2f9d 100644
--- a/docs/zh/docs/tutorial/dependencies/global-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/global-dependencies.md
@@ -1,17 +1,34 @@
# 全局依赖项
-有时,我们要为整个应用添加依赖项。
+For some types of applications you might want to add dependencies to the whole application.
通过与定义[*路径装饰器依赖项*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 类似的方式,可以把依赖项添加至整个 `FastAPI` 应用。
这样一来,就可以为所有*路径操作*应用该依赖项:
-```Python hl_lines="15"
-{!../../../docs_src/dependencies/tutorial012.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="16"
+ 有时,我们要为整个应用添加依赖项。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="16"
+ 为一组路径操作定义依赖项
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="15"
+ {!../../../docs_src/dependencies/tutorial012.py!}
+ ```
[*路径装饰器依赖项*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} 一章的思路均适用于全局依赖项, 在本例中,这些依赖项可以用于应用中的所有*路径操作*。
-## 为一组路径操作定义依赖项
+## Dependencies for groups of *path operations*
稍后,[大型应用 - 多文件](../../tutorial/bigger-applications.md){.internal-link target=_blank}一章中会介绍如何使用多个文件创建大型应用程序,在这一章中,您将了解到如何为一组*路径操作*声明单个 `dependencies` 参数。
diff --git a/docs/zh/docs/tutorial/dependencies/index.md b/docs/zh/docs/tutorial/dependencies/index.md
index 7a133061de797..18a301d8e46b0 100644
--- a/docs/zh/docs/tutorial/dependencies/index.md
+++ b/docs/zh/docs/tutorial/dependencies/index.md
@@ -10,18 +10,18 @@ FastAPI 提供了简单易用,但功能强大的** ../../../docs_src/dependencies/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ {!../../../docs_src/dependencies/tutorial001.py!}
+ ```
+
+### Declare the dependency, in the "dependant"
与在*路径操作函数*参数中使用 `Body`、`Query` 的方式相同,声明依赖项需要使用 `Depends` 和一个新的参数:
-```Python hl_lines="15 20"
-{!../../../docs_src/dependencies/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="13 18"
+ 外部支持库
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="15 20"
+ 声明依赖项
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="16 21"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11 16"
+ {!> ../../../docs_src/dependencies/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="15 20"
+ !!! note "笔记"
+ ```
虽然,在路径操作函数的参数中使用 `Depends` 的方式与 `Body`、`Query` 相同,但 `Depends` 的工作方式略有不同。
-这里只能传给 Depends 一个参数。
+You only give `Depends` a single parameter.
且该参数必须是可调用对象,比如函数。
+上述场景均可以使用**依赖注入**,将代码重复最小化。
+
该函数接收的参数和*路径操作函数*的参数一样。
-!!! tip "提示"
-
- 下一章介绍,除了函数还有哪些「对象」可以用作依赖项。
+!!! tip
+ You'll see what other "things", apart from functions, can be used as dependencies in the next chapter.
接收到新的请求时,**FastAPI** 执行如下操作:
@@ -98,12 +202,49 @@ common_parameters --> read_users
这样,只编写一次代码,**FastAPI** 就可以为多个*路径操作*共享这段代码 。
-!!! check "检查"
-
- 注意,无需创建专门的类,并将之传递给 **FastAPI** 以进行「注册」或执行类似的操作。
+!!! 注意,无需创建专门的类,并将之传递给 **FastAPI** 以进行「注册」或执行类似的操作。
只要把它传递给 `Depends`,**FastAPI** 就知道该如何执行后续操作。
+## Share `Annotated` dependencies
+
+接下来,我们学习一个非常简单的例子,尽管它过于简单,不是很实用。
+
+When you need to use the `common_parameters()` dependency, you have to write the whole parameter with the type annotation and `Depends()`:
+
+```Python
+commons: Annotated[dict, Depends(common_parameters)]
+```
+
+But because we are using `Annotated`, we can store that `Annotated` value in a variable and use it in multiple places:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="12 16 21"
+ 开发人员可以使用依赖项及其子依赖项为这些路径操作添加不同的权限:
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14 18 23"
+ 等……
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15 19 24"
+ 依赖项可以返回各种内容。
+ ```
+
+!!! tip
+ This is just standard Python, it's called a "type alias", it's actually not specific to **FastAPI**.
+
+ But because **FastAPI** is based on the Python standards, including `Annotated`, you can use this trick in your code. 😎
+
+The dependencies will keep working as expected, and the **best part** is that the **type information will be preserved**, which means that your editor will be able to keep providing you with **autocompletion**, **inline errors**, etc. The same for other tools like `mypy`.
+
+上述这些操作都是可行的,**FastAPI** 知道该怎么处理。
+
## 要不要使用 `async`?
**FastAPI** 调用依赖项的方式与*路径操作函数*一样,因此,定义依赖项函数,也要应用与路径操作函数相同的规则。
@@ -112,11 +253,10 @@ common_parameters --> read_users
在普通的 `def` *路径操作函数*中,可以声明异步的 `async def` 依赖项;也可以在异步的 `async def` *路径操作函数*中声明普通的 `def` 依赖项。
-上述这些操作都是可行的,**FastAPI** 知道该怎么处理。
-
-!!! note "笔记"
+It doesn't matter. 然后,**FastAPI** 会用正确的参数调用函数,并提取请求中的数据。
- 如里不了解异步,请参阅[异步:*“着急了?”*](../../async.md){.internal-link target=_blank} 一章中 `async` 和 `await` 的内容。
+!!! note
+ If you don't know, check the [Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank} section about `async` and `await` in the docs.
## 与 OpenAPI 集成
@@ -124,15 +264,15 @@ common_parameters --> read_users
所以,交互文档里也会显示依赖项的所有信息:
-
+
## 简单用法
-观察一下就会发现,只要*路径* 和*操作*匹配,就可以使用声明的路径操作函数。然后,**FastAPI** 会用正确的参数调用函数,并提取请求中的数据。
+开发人员永远都不需要直接调用这些函数,这些函数是由框架(在此为 **FastAPI** )调用的。
实际上,所有(或大多数)网络框架的工作方式都是这样的。
-开发人员永远都不需要直接调用这些函数,这些函数是由框架(在此为 **FastAPI** )调用的。
+You never call those functions directly. They are called by your framework (in this case, **FastAPI**).
通过依赖注入系统,只要告诉 **FastAPI** *路径操作函数* 还要「依赖」其他在*路径操作函数*之前执行的内容,**FastAPI** 就会执行函数代码,并「注入」函数返回的结果。
@@ -144,21 +284,21 @@ common_parameters --> read_users
* 可注入(Injectable)
* 组件(Component)
-## **FastAPI** 插件
+## **FastAPI** 兼容性
-**依赖注入**系统支持构建集成和「插件」。但实际上,FastAPI 根本**不需要创建「插件」**,因为使用依赖项可以声明不限数量的、可用于*路径操作函数*的集成与交互。
+**依赖注入**系统支持构建集成和「插件」。 但实际上,FastAPI 根本**不需要创建「插件」**,因为使用依赖项可以声明不限数量的、可用于*路径操作函数*的集成与交互。
-创建依赖项非常简单、直观,并且还支持导入 Python 包。毫不夸张地说,只要几行代码就可以把需要的 Python 包与 API 函数集成在一起。
+创建依赖项非常简单、直观,并且还支持导入 Python 包。 毫不夸张地说,只要几行代码就可以把需要的 Python 包与 API 函数集成在一起。
下一章将详细介绍在关系型数据库、NoSQL 数据库、安全等方面使用依赖项的例子。
-## **FastAPI** 兼容性
+## **FastAPI** 插件
依赖注入系统如此简洁的特性,让 **FastAPI** 可以与下列系统兼容:
* 关系型数据库
* NoSQL 数据库
-* 外部支持库
+* external packages
* 外部 API
* 认证和鉴权系统
* API 使用监控系统
@@ -180,7 +320,7 @@ common_parameters --> read_users
* `/users/{user_id}/activate`
* `/items/pro/`
-开发人员可以使用依赖项及其子依赖项为这些路径操作添加不同的权限:
+then you could add different permission requirements for each of them just with dependencies and sub-dependencies:
```mermaid
graph TB
diff --git a/docs/zh/docs/tutorial/dependencies/sub-dependencies.md b/docs/zh/docs/tutorial/dependencies/sub-dependencies.md
index 58377bbfecd8d..fa61d94fa0bb3 100644
--- a/docs/zh/docs/tutorial/dependencies/sub-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/sub-dependencies.md
@@ -6,25 +6,89 @@ FastAPI 支持创建含**子依赖项**的依赖项。
**FastAPI** 负责处理解析不同深度的子依赖项。
-### 第一层依赖项
+## 第一层依赖项
-下列代码创建了第一层依赖项:
+You could create a first dependency ("dependable") like:
-```Python hl_lines="8-9"
-{!../../../docs_src/dependencies/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="8-9"
+ 这个函数很简单(不过也没什么用),但却有助于让我们专注于了解子依赖项的工作方式。
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="8-9"
+ 小结
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-10"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.10 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6-7"
+ {!../../../docs_src/dependencies/tutorial005.py!}
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8-9"
+ {!> ../../../docs_src/dependencies/tutorial005.py!}
+ ```
这段代码声明了类型为 `str` 的可选查询参数 `q`,然后返回这个查询参数。
-这个函数很简单(不过也没什么用),但却有助于让我们专注于了解子依赖项的工作方式。
+This is quite simple (not very useful), but will help us focus on how the sub-dependencies work.
-### 第二层依赖项
+## Second dependency, "dependable" and "dependant"
接下来,创建另一个依赖项函数,并同时用该依赖项自身再声明一个依赖项(所以这也是一个「依赖项」):
-```Python hl_lines="13"
-{!../../../docs_src/dependencies/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/dependencies/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="13"
+ 下列代码创建了第一层依赖项:
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/dependencies/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/dependencies/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="13"
+ {!../../../docs_src/dependencies/tutorial005.py!}
+ ```
这里重点说明一下声明的参数:
@@ -33,17 +97,47 @@ FastAPI 支持创建含**子依赖项**的依赖项。
* 同时,该函数还声明了类型是 `str` 的可选 cookie(`last_query`)
* 用户未提供查询参数 `q` 时,则使用上次使用后保存在 cookie 中的查询
-### 使用依赖项
+## 使用依赖项
接下来,就可以使用依赖项:
-```Python hl_lines="22"
-{!../../../docs_src/dependencies/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/dependencies/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="23"
+ 第二层依赖项
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24"
+ !!! info "信息"
+ ```
+
+=== "Python 3.10 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
-!!! info "信息"
+ ```Python hl_lines="22"
+ {!../../../docs_src/dependencies/tutorial005.py!}
+ ```
- 注意,这里在*路径操作函数*中只声明了一个依赖项,即 `query_or_cookie_extractor` 。
+!!! 注意,这里在*路径操作函数*中只声明了一个依赖项,即 `query_or_cookie_extractor` 。
但 **FastAPI** 必须先处理 `query_extractor`,以便在调用 `query_or_cookie_extractor` 时使用 `query_extractor` 返回的结果。
@@ -66,12 +160,27 @@ FastAPI 不会为同一个请求多次调用同一个依赖项,而是把依赖
在高级使用场景中,如果不想使用「缓存」值,而是为需要在同一请求的每一步操作(多次)中都实际调用依赖项,可以把 `Depends` 的参数 `use_cache` 的值设置为 `False` :
-```Python hl_lines="1"
-async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ 这些简单的例子现在看上去虽然没有什么实用价值,
+
+但在**安全**一章中,您会了解到这些例子的用途,
+
+以及这些例子所能节省的代码量。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
return {"fresh_value": fresh_value}
-```
+ ```
-## 小结
+## Recap
千万别被本章里这些花里胡哨的词藻吓倒了,其实**依赖注入**系统非常简单。
@@ -79,10 +188,9 @@ async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False
但它依然非常强大,能够声明任意嵌套深度的「图」或树状的依赖结构。
-!!! tip "提示"
-
- 这些简单的例子现在看上去虽然没有什么实用价值,
-
- 但在**安全**一章中,您会了解到这些例子的用途,
+!!! tip
+ All this might not seem as useful with these simple examples.
- 以及这些例子所能节省的代码量。
+ But you will see how useful it is in the chapters about **security**.
+
+ And you will also see the amounts of code it will save you.
diff --git a/docs/zh/docs/tutorial/encoder.md b/docs/zh/docs/tutorial/encoder.md
index 76ed846ce35e4..3c0b9152fc1dd 100644
--- a/docs/zh/docs/tutorial/encoder.md
+++ b/docs/zh/docs/tutorial/encoder.md
@@ -36,7 +36,7 @@
调用它的结果后就可以使用Python标准编码中的`json.dumps()`。
-这个操作不会返回一个包含JSON格式(作为字符串)数据的庞大的`str`。它将返回一个Python标准数据结构(例如`dict`),其值和子值都与JSON兼容。
+这个操作不会返回一个包含JSON格式(作为字符串)数据的庞大的`str`。 它将返回一个Python标准数据结构(例如`dict`),其值和子值都与JSON兼容。
-!!! note
- `jsonable_encoder`实际上是FastAPI内部用来转换数据的。但是它在许多其他场景中也很有用。
+!!! !!! note
+ `jsonable_encoder`实际上是FastAPI内部用来转换数据的。 但是它在许多其他场景中也很有用。
diff --git a/docs/zh/docs/tutorial/extra-data-types.md b/docs/zh/docs/tutorial/extra-data-types.md
index ac3e076545f48..60fc4c3bc68df 100644
--- a/docs/zh/docs/tutorial/extra-data-types.md
+++ b/docs/zh/docs/tutorial/extra-data-types.md
@@ -55,12 +55,76 @@
下面是一个*路径操作*的示例,其中的参数使用了上面的一些类型。
-```Python hl_lines="1 3 12-16"
-{!../../../docs_src/extra_data_types/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 3 13-17"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1 2 11-15"
+ {!../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1 2 12-16"
+ {!../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
注意,函数内的参数有原生的数据类型,你可以,例如,执行正常的日期操作,如:
-```Python hl_lines="18-19"
-{!../../../docs_src/extra_data_types/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="19-20"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
diff --git a/docs/zh/docs/tutorial/extra-models.md b/docs/zh/docs/tutorial/extra-models.md
index 1fbe77be8de70..1a1f3c3354ca8 100644
--- a/docs/zh/docs/tutorial/extra-models.md
+++ b/docs/zh/docs/tutorial/extra-models.md
@@ -8,8 +8,8 @@
* **输出模型**不应该包含密码。
* **数据库模型**很可能需要保存密码的哈希值。
-!!! danger
- 永远不要存储用户的明文密码。始终存储一个可以用于验证的「安全哈希值」。
+!!! !!! danger
+ 永远不要存储用户的明文密码。 始终存储一个可以用于验证的「安全哈希值」。
如果你尚未了解该知识,你可以在[安全章节](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}中学习何为「密码哈希值」。
@@ -17,9 +17,17 @@
下面是应该如何根据它们的密码字段以及使用位置去定义模型的大概思路:
-```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
-{!../../../docs_src/extra_models/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
+ {!> ../../../docs_src/extra_models/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
+ {!../../../docs_src/extra_models/tutorial001.py!}
+ ```
### 关于 `**user_in.dict()`
@@ -62,7 +70,7 @@ print(user_dict)
#### 解包 `dict`
-如果我们将 `user_dict` 这样的 `dict` 以 `**user_dict` 形式传递给一个函数(或类),Python将对其进行「解包」。它会将 `user_dict` 的键和值作为关键字参数直接传递。
+如果我们将 `user_dict` 这样的 `dict` 以 `**user_dict` 形式传递给一个函数(或类),Python将对其进行「解包」。 它会将 `user_dict` 的键和值作为关键字参数直接传递。
因此,从上面的 `user_dict` 继续,编写:
@@ -94,7 +102,7 @@ UserInDB(
#### 来自于其他模型内容的 Pydantic 模型
-如上例所示,我们从 `user_in.dict()` 中获得了 `user_dict`,此代码:
+...因为 `user_in.dict()` 是一个 `dict`,然后我们通过以`**`开头传递给 `UserInDB` 来使 Python「解包」它。
```Python
user_dict = user_in.dict()
@@ -107,7 +115,7 @@ UserInDB(**user_dict)
UserInDB(**user_in.dict())
```
-...因为 `user_in.dict()` 是一个 `dict`,然后我们通过以`**`开头传递给 `UserInDB` 来使 Python「解包」它。
+如上例所示,我们从 `user_in.dict()` 中获得了 `user_dict`,此代码:
这样,我们获得了一个来自于其他 Pydantic 模型中的数据的 Pydantic 模型。
@@ -132,7 +140,7 @@ UserInDB(
```
!!! warning
- 辅助性的额外函数只是为了演示可能的数据流,但它们显然不能提供任何真正的安全性。
+ The supporting additional functions are just to demo a possible flow of the data, but they of course are not providing any real security.
## 减少重复
@@ -144,15 +152,23 @@ UserInDB(
我们可以做得更好。
-我们可以声明一个 `UserBase` 模型作为其他模型的基类。然后我们可以创建继承该模型属性(类型声明,校验等)的子类。
+我们可以声明一个 `UserBase` 模型作为其他模型的基类。 然后我们可以创建继承该模型属性(类型声明,校验等)的子类。
所有的数据转换、校验、文档生成等仍将正常运行。
这样,我们可以仅声明模型之间的差异部分(具有明文的 `password`、具有 `hashed_password` 以及不包括密码)。
-```Python hl_lines="9 15-16 19-20 23-24"
-{!../../../docs_src/extra_models/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 13-14 17-18 21-22"
+ {!> ../../../docs_src/extra_models/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 15-16 19-20 23-24"
+ {!../../../docs_src/extra_models/tutorial002.py!}
+ ```
## `Union` 或者 `anyOf`
@@ -162,23 +178,53 @@ UserInDB(
为此,请使用标准的 Python 类型提示 `typing.Union`:
+!!! !!! note
+ 定义一个 `Union` 类型时,首先包括最详细的类型,然后是不太详细的类型。 在下面的示例中,更详细的 `PlaneItem` 位于 `Union[PlaneItem,CarItem]` 中的 `CarItem` 之前。
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!> ../../../docs_src/extra_models/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
-!!! note
- 定义一个 `Union` 类型时,首先包括最详细的类型,然后是不太详细的类型。在下面的示例中,更详细的 `PlaneItem` 位于 `Union[PlaneItem,CarItem]` 中的 `CarItem` 之前。
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!../../../docs_src/extra_models/tutorial003.py!}
+ ```
-```Python hl_lines="1 14-15 18-20 33"
-{!../../../docs_src/extra_models/tutorial003.py!}
+### `Union` in Python 3.10
+
+In this example we pass `Union[PlaneItem, CarItem]` as the value of the argument `response_model`.
+
+Because we are passing it as a **value to an argument** instead of putting it in a **type annotation**, we have to use `Union` even in Python 3.10.
+
+If it was in a type annotation we could have used the vertical bar, as:
+
+```Python
+some_variable: PlaneItem | CarItem
```
+But if we put that in `response_model=PlaneItem | CarItem` we would get an error, because Python would try to perform an **invalid operation** between `PlaneItem` and `CarItem` instead of interpreting that as a type annotation.
+
## 模型列表
你可以用同样的方式声明由对象列表构成的响应。
为此,请使用标准的 Python `typing.List`:
-```Python hl_lines="1 20"
-{!../../../docs_src/extra_models/tutorial004.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="18"
+ !!! warning
+ 辅助性的额外函数只是为了演示可能的数据流,但它们显然不能提供任何真正的安全性。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 20"
+ {!../../../docs_src/extra_models/tutorial004.py!}
+ ```
## 任意 `dict` 构成的响应
@@ -188,12 +234,20 @@ UserInDB(
在这种情况下,你可以使用 `typing.Dict`:
-```Python hl_lines="1 8"
-{!../../../docs_src/extra_models/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="6"
+ 总结
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 8"
+ {!../../../docs_src/extra_models/tutorial005.py!}
+ ```
-## 总结
+## Recap
使用多个 Pydantic 模型,并针对不同场景自由地继承。
-如果一个实体必须能够具有不同的「状态」,你无需为每个状态的实体定义单独的数据模型。以用户「实体」为例,其状态有包含 `password`、包含 `password_hash` 以及不含密码。
+如果一个实体必须能够具有不同的「状态」,你无需为每个状态的实体定义单独的数据模型。 以用户「实体」为例,其状态有包含 `password`、包含 `password_hash` 以及不含密码。
diff --git a/docs/zh/docs/tutorial/first-steps.md b/docs/zh/docs/tutorial/first-steps.md
index 30fae99cf8fc2..597e8e6f89acf 100644
--- a/docs/zh/docs/tutorial/first-steps.md
+++ b/docs/zh/docs/tutorial/first-steps.md
@@ -21,16 +21,17 @@ $ uvicorn main:app --reload
INFO: Waiting for application startup.
INFO: Application startup complete.
```
+INFO: Application startup complete.
+```
get 操作
-!!! info "`@decorator` Info"
- `@something` 语法在 Python 中被称为「装饰器」。
-
- 像一顶漂亮的装饰帽一样,将它放在一个函数的上方(我猜测这个术语的命名就是这么来的)。
+!!! !!! info "`@decorator` Info" `@something` 语法在 Python 中被称为「装饰器」。
+ You put it on top of a function. 像一顶漂亮的装饰帽一样,将它放在一个函数的上方(我猜测这个术语的命名就是这么来的)。
+
装饰器接收位于其下方的函数并且用它完成一些工作。
-
+
在我们的例子中,这个装饰器告诉 **FastAPI** 位于其下方的函数对应着**路径** `/` 加上 `get` **操作**。
-
+
它是一个「**路径操作装饰器**」。
你也可以使用其他的操作:
@@ -276,13 +275,13 @@ https://example.com/items/foo
* `@app.patch()`
* `@app.trace()`
-!!! tip
+!!! !!! tip
您可以随意使用任何一个操作(HTTP方法)。
**FastAPI** 没有强制要求操作有任何特定的含义。
-
+
此处提供的信息仅作为指导,而不是要求。
-
+
比如,当使用 GraphQL 时通常你所有的动作都通过 `post` 一种方法执行。
### 步骤 4:定义**路径操作函数**
@@ -311,7 +310,7 @@ https://example.com/items/foo
{!../../../docs_src/first_steps/tutorial003.py!}
```
-!!! note
+!!! !!! note
如果你不知道两者的区别,请查阅 [Async: *"In a hurry?"*](https://fastapi.tiangolo.com/async/#in-a-hurry){.internal-link target=_blank}。
### 步骤 5:返回内容
@@ -324,9 +323,9 @@ https://example.com/items/foo
你还可以返回 Pydantic 模型(稍后你将了解更多)。
-还有许多其他将会自动转换为 JSON 的对象和模型(包括 ORM 对象等)。尝试下使用你最喜欢的一种,它很有可能已经被支持。
+还有许多其他将会自动转换为 JSON 的对象和模型(包括 ORM 对象等)。 尝试下使用你最喜欢的一种,它很有可能已经被支持。
-## 总结
+## Recap
* 导入 `FastAPI`。
* 创建一个 `app` 实例。
diff --git a/docs/zh/docs/tutorial/handling-errors.md b/docs/zh/docs/tutorial/handling-errors.md
index 9b066bc2cee65..46a31245ea790 100644
--- a/docs/zh/docs/tutorial/handling-errors.md
+++ b/docs/zh/docs/tutorial/handling-errors.md
@@ -4,18 +4,18 @@
这里所谓的客户端包括前端浏览器、其他应用程序、物联网设备等。
-需要向客户端返回错误提示的场景主要如下:
+You could need to tell the client that:
-- 客户端没有执行操作的权限
-- 客户端没有访问资源的权限
-- 客户端要访问的项目不存在
-- 等等 ...
+* 客户端没有执行操作的权限
+* 客户端没有访问资源的权限
+* 客户端要访问的项目不存在
+* etc.
遇到这些情况时,通常要返回 **4XX**(400 至 499)**HTTP 状态码**。
-**4XX** 状态码与表示请求成功的 **2XX**(200 至 299) HTTP 状态码类似。
+This is similar to the 200 HTTP status codes (from 200 to 299). Those "200" status codes mean that somehow there was a "success" in the request.
-只不过,**4XX** 状态码表示客户端发生的错误。
+The status codes in the 400 range mean that there was an error from the client.
大家都知道**「404 Not Found」**错误,还有调侃这个错误的笑话吧?
@@ -27,7 +27,6 @@
```Python hl_lines="1"
{!../../../docs_src/handling_errors/tutorial001.py!}
-
```
### 触发 `HTTPException`
@@ -44,7 +43,6 @@
```Python hl_lines="11"
{!../../../docs_src/handling_errors/tutorial001.py!}
-
```
### 响应结果
@@ -55,7 +53,6 @@
{
"item": "The Foo Wrestlers"
}
-
```
但如果客户端请求 `http://example.com/items/bar`(`item_id` `「bar」` 不存在时),则会接收到 HTTP 状态码 - 404(「未找到」错误)及如下 JSON 响应结果:
@@ -64,21 +61,15 @@
{
"detail": "Item not found"
}
-
```
-!!! tip "提示"
-
- 触发 `HTTPException` 时,可以用参数 `detail` 传递任何能转换为 JSON 的值,不仅限于 `str`。
-
- 还支持传递 `dict`、`list` 等数据结构。
-
- **FastAPI** 能自动处理这些数据,并将之转换为 JSON。
+!!! 触发 `HTTPException` 时,可以用参数 `detail` 传递任何能转换为 JSON 的值,不仅限于 `str`。
+ 还支持传递 `dict`、`list` 等数据结构。 **FastAPI** 能自动处理这些数据,并将之转换为 JSON。
## 添加自定义响应头
-有些场景下要为 HTTP 错误添加自定义响应头。例如,出于某些方面的安全需要。
+有些场景下要为 HTTP 错误添加自定义响应头。 例如,出于某些方面的安全需要。
一般情况下可能不会需要在代码中直接使用响应头。
@@ -86,7 +77,6 @@
```Python hl_lines="14"
{!../../../docs_src/handling_errors/tutorial002.py!}
-
```
## 安装自定义异常处理器
@@ -101,7 +91,6 @@
```Python hl_lines="5-7 13-18 24"
{!../../../docs_src/handling_errors/tutorial003.py!}
-
```
请求 `/unicorns/yolo` 时,路径操作会触发 `UnicornException`。
@@ -111,30 +100,27 @@
接收到的错误信息清晰明了,HTTP 状态码为 `418`,JSON 内容如下:
```JSON
-{"message": "Oops! yolo did something. There goes a rainbow..."}
-
+{"message": "Oops! yolo did something. {"message": "Oops! yolo did something. There goes a rainbow..."}
```
-!!! note "技术细节"
-
- `from starlette.requests import Request` 和 `from starlette.responses import JSONResponse` 也可以用于导入 `Request` 和 `JSONResponse`。
+!!! note "Technical Details"
+ You could also use `from starlette.requests import Request` and `from starlette.responses import JSONResponse`.
- **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应操作都可以直接从 Starlette 导入。同理,`Request` 也是如此。
+ `from starlette.requests import Request` 和 `from starlette.responses import JSONResponse` 也可以用于导入 `Request` 和 `JSONResponse`。 **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应操作都可以直接从 Starlette 导入。 同理,`Request` 也是如此。
-
-## 覆盖默认异常处理器
+## Override the default exception handlers
**FastAPI** 自带了一些默认异常处理器。
触发 `HTTPException` 或请求无效数据时,这些处理器返回默认的 JSON 响应结果。
-不过,也可以使用自定义处理器覆盖默认异常处理器。
+You can override these exception handlers with your own.
### 覆盖请求验证异常
请求中包含无效数据时,**FastAPI** 内部会触发 `RequestValidationError`。
-该异常也内置了默认异常处理器。
+And it also includes a default exception handler for it.
覆盖默认异常处理器时需要导入 `RequestValidationError`,并用 `@app.excption_handler(RequestValidationError)` 装饰异常处理器。
@@ -142,7 +128,6 @@
```Python hl_lines="2 14-16"
{!../../../docs_src/handling_errors/tutorial004.py!}
-
```
访问 `/items/foo`,可以看到以下内容替换了默认 JSON 错误信息:
@@ -160,30 +145,26 @@
}
]
}
-
```
-以下是文本格式的错误信息:
+you will get a text version, with:
```
1 validation error
path -> item_id
value is not a valid integer (type=type_error.integer)
-
```
-### `RequestValidationError` vs `ValidationError`
-
-!!! warning "警告"
-
- 如果您觉得现在还用不到以下技术细节,可以先跳过下面的内容。
+#### `RequestValidationError` vs `ValidationError`
+!!! warning
+ These are technical details that you might skip if it's not important for you now.
`RequestValidationError` 是 Pydantic 的 `ValidationError` 的子类。
**FastAPI** 调用的就是 `RequestValidationError` 类,因此,如果在 `response_model` 中使用 Pydantic 模型,且数据有错误时,在日志中就会看到这个错误。
-但客户端或用户看不到这个错误。反之,客户端接收到的是 HTTP 状态码为 `500` 的「内部服务器错误」。
+但客户端或用户看不到这个错误。 反之,客户端接收到的是 HTTP 状态码为 `500` 的「内部服务器错误」。
这是因为在*响应*或代码(不是在客户端的请求里)中出现的 Pydantic `ValidationError` 是代码的 bug。
@@ -197,15 +178,12 @@ path -> item_id
```Python hl_lines="3-4 9-11 22"
{!../../../docs_src/handling_errors/tutorial004.py!}
-
```
-!!! note "技术细节"
-
- 还可以使用 `from starlette.responses import PlainTextResponse`。
-
- **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应都可以直接从 Starlette 导入。
+!!! note "Technical Details"
+ You could also use `from starlette.responses import PlainTextResponse`.
+ 还可以使用 `from starlette.responses import PlainTextResponse`。 **FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为快捷方式,但大部分响应都可以直接从 Starlette 导入。
### 使用 `RequestValidationError` 的请求体
@@ -215,7 +193,6 @@ path -> item_id
```Python hl_lines="14"
{!../../../docs_src/handling_errors/tutorial005.py!}
-
```
现在试着发送一个无效的 `item`,例如:
@@ -225,7 +202,6 @@ path -> item_id
"title": "towel",
"size": "XL"
}
-
```
收到的响应包含 `body` 信息,并说明数据是无效的:
@@ -247,10 +223,9 @@ path -> item_id
"size": "XL"
}
}
-
```
-### FastAPI `HTTPException` vs Starlette `HTTPException`
+#### FastAPI `HTTPException` vs Starlette `HTTPException`
**FastAPI** 也提供了自有的 `HTTPException`。
@@ -270,20 +245,14 @@ OAuth 2.0 等安全工具需要在内部调用这些响应头。
```Python
from starlette.exceptions import HTTPException as StarletteHTTPException
-
```
### 复用 **FastAPI** 异常处理器
FastAPI 支持先对异常进行某些处理,然后再使用 **FastAPI** 中处理该异常的默认异常处理器。
-从 `fastapi.exception_handlers` 中导入要复用的默认异常处理器:
-
```Python hl_lines="2-5 15 21"
{!../../../docs_src/handling_errors/tutorial006.py!}
-
```
-虽然,本例只是输出了夸大其词的错误信息。
-
-但也足以说明,可以在处理异常之后再复用默认的异常处理器。
+In this example you are just `print`ing the error with a very expressive message, but you get the idea. You can use the exception and then just re-use the default exception handlers.
diff --git a/docs/zh/docs/tutorial/header-params.md b/docs/zh/docs/tutorial/header-params.md
index c4b1c38ceecc8..945345f38ef25 100644
--- a/docs/zh/docs/tutorial/header-params.md
+++ b/docs/zh/docs/tutorial/header-params.md
@@ -6,9 +6,41 @@
首先导入 `Header`:
-```Python hl_lines="3"
-{!../../../docs_src/header_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/header_params/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ {!../../../docs_src/header_params/tutorial002.py!}
+ ```
## 声明 `Header` 参数
@@ -16,17 +48,49 @@
第一个值是默认值,你可以传递所有的额外验证或注释参数:
-```Python hl_lines="9"
-{!../../../docs_src/header_params/tutorial001.py!}
-```
+=== "Python 3.10+"
-!!! note "技术细节"
- `Header` 是 `Path`, `Query` 和 `Cookie` 的兄弟类型。它也继承自通用的 `Param` 类.
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
+
+!!! !!! note "技术细节"
+ `Header` 是 `Path`, `Query` 和 `Cookie` 的兄弟类型。 它也继承自通用的 `Param` 类.
但是请记得,当你从`fastapi`导入 `Query`, `Path`, `Header`, 或其他时,实际上导入的是返回特定类型的函数。
!!! info
- 为了声明headers, 你需要使用`Header`, 因为否则参数将被解释为查询参数。
+ To declare headers, you need to use `Header`, because otherwise the parameters would be interpreted as query parameters.
## 自动转换
@@ -44,17 +108,51 @@
如果出于某些原因,你需要禁用下划线到连字符的自动转换,设置`Header`的参数 `convert_underscores` 为 `False`:
-```Python hl_lines="10"
-{!../../../docs_src/header_params/tutorial002.py!}
-```
+=== "Python 3.10+"
-!!! warning
- 在设置 `convert_underscores` 为 `False` 之前,请记住,一些HTTP代理和服务器不允许使用带有下划线的headers。
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002_an_py310.py!}
+ ```
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ !!! info
+ 为了声明headers, 你需要使用Header, 因为否则参数将被解释为查询参数。
+ ```
+, 因为否则参数将被解释为查询参数。
+
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/header_params/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/header_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!../../../docs_src/header_params/tutorial001.py!}
+ ```
+
+!!! warning
+ Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.
## 重复的 headers
-有可能收到重复的headers。这意味着,相同的header具有多个值。
+有可能收到重复的headers。 这意味着,相同的header具有多个值。
您可以在类型声明中使用一个list来定义这些情况。
@@ -62,9 +160,53 @@
比如, 为了声明一个 `X-Token` header 可以出现多次,你可以这样写:
-```Python hl_lines="9"
-{!../../../docs_src/header_params/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ !!! warning
+ 在设置 convert_underscores 为 False 之前,请记住,一些HTTP代理和服务器不允许使用带有下划线的headers。
+ ```
+ 为 False 之前,请记住,一些HTTP代理和服务器不允许使用带有下划线的headers。
+
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/header_params/tutorial003.py!}
+ ```
如果你与*路径操作*通信时发送两个HTTP headers,就像:
diff --git a/docs/zh/docs/tutorial/index.md b/docs/zh/docs/tutorial/index.md
index 6180d3de399ae..e9f55adc42962 100644
--- a/docs/zh/docs/tutorial/index.md
+++ b/docs/zh/docs/tutorial/index.md
@@ -25,10 +25,12 @@ $ uvicorn main:app --reload
INFO: Waiting for application startup.
INFO: Application startup complete.
```
+INFO: Application startup complete.
+```
-
-## 标签元数据
-
-你也可以使用参数 `openapi_tags`,为用于分组路径操作的不同标签添加额外的元数据。
-
-它接受一个列表,这个列表包含每个标签对应的一个字典。
-
-每个字典可以包含:
-
-* `name`(**必要**):一个 `str`,它与*路径操作*和 `APIRouter` 中使用的 `tags` 参数有相同的标签名。
-* `description`:一个用于简短描述标签的 `str`。它支持 Markdown 并且会在文档用户界面中显示。
-* `externalDocs`:一个描述外部文档的 `dict`:
- * `description`:用于简短描述外部文档的 `str`。
- * `url`(**必要**):外部文档的 URL `str`。
-
-### 创建标签元数据
-
-让我们在带有标签的示例中为 `users` 和 `items` 试一下。
-
-创建标签元数据并把它传递给 `openapi_tags` 参数:
-
-```Python hl_lines="3-16 18"
-{!../../../docs_src/metadata/tutorial004.py!}
-```
-
-注意你可以在描述内使用 Markdown,例如「login」会显示为粗体(**login**)以及「fancy」会显示为斜体(_fancy_)。
-
-!!! 提示
- 不必为你使用的所有标签都添加元数据。
-
-### 使用你的标签
-
-将 `tags` 参数和*路径操作*(以及 `APIRouter`)一起使用,将其分配给不同的标签:
-
-```Python hl_lines="21 26"
-{!../../../docs_src/metadata/tutorial004.py!}
-```
-
-!!! 信息
- 阅读更多关于标签的信息[路径操作配置](../path-operation-configuration/#tags){.internal-link target=_blank}。
-
-### 查看文档
-
-如果你现在查看文档,它们会显示所有附加的元数据:
-
-
-
-### 标签顺序
-
-每个标签元数据字典的顺序也定义了在文档用户界面显示的顺序。
-
-例如按照字母顺序,即使 `users` 排在 `items` 之后,它也会显示在前面,因为我们将它的元数据添加为列表内的第一个字典。
-
-## OpenAPI URL
-
-默认情况下,OpenAPI 模式服务于 `/openapi.json`。
-
-但是你可以通过参数 `openapi_url` 对其进行配置。
-
-例如,将其设置为服务于 `/api/v1/openapi.json`:
-
-```Python hl_lines="3"
-{!../../../docs_src/metadata/tutorial002.py!}
-```
-
-如果你想完全禁用 OpenAPI 模式,可以将其设置为 `openapi_url=None`,这样也会禁用使用它的文档用户界面。
-
-## 文档 URLs
-
-你可以配置两个文档用户界面,包括:
-
-* **Swagger UI**:服务于 `/docs`。
- * 可以使用参数 `docs_url` 设置它的 URL。
- * 可以通过设置 `docs_url=None` 禁用它。
-* ReDoc:服务于 `/redoc`。
- * 可以使用参数 `redoc_url` 设置它的 URL。
- * 可以通过设置 `redoc_url=None` 禁用它。
-
-例如,设置 Swagger UI 服务于 `/documentation` 并禁用 ReDoc:
-
-```Python hl_lines="3"
-{!../../../docs_src/metadata/tutorial003.py!}
-```
+# 元数据和文档 URL
+
+你可以在 **FastAPI** 应用中自定义几个元数据配置。
+
+## Metadata for API
+
+**Description**:在 OpenAPI 和自动 API 文档用户界面中用作 API 的描述。
+| The license information for the exposed API. It can contain several fields.
+
+## License identifier
+
+Since OpenAPI 3.1.0 and FastAPI 0.99.0, you can also set the `license_info` with an `identifier` instead of a `url`.
+
+For example:
+
+```Python hl_lines="31"
+{!../../../docs_src/metadata/tutorial001_1.py!}
+```
+
+## 标签元数据
+
+你也可以使用参数 `openapi_tags`,为用于分组路径操作的不同标签添加额外的元数据。
+
+它接受一个列表,这个列表包含每个标签对应的一个字典。
+
+每个字典可以包含:
+
+* `name`(**必要**):一个 `str`,它与*路径操作*和 `APIRouter` 中使用的 `tags` 参数有相同的标签名。
+* `description`:一个用于简短描述标签的 `str`。 它支持 Markdown 并且会在文档用户界面中显示。
+* `externalDocs`:一个描述外部文档的 `dict`:
+ * `description`:用于简短描述外部文档的 `str`。
+ * `url`(**必要**):外部文档的 URL `str`。
+
+### 创建标签元数据
+
+让我们在带有标签的示例中为 `users` 和 `items` 试一下。
+
+创建标签元数据并把它传递给 `openapi_tags` 参数:
+
+```Python hl_lines="3-16 18"
+{!../../../docs_src/metadata/tutorial004.py!}
+```
+
+注意你可以在描述内使用 Markdown,例如「login」会显示为粗体(**login**)以及「fancy」会显示为斜体(_fancy_)。
+
+!!! !!! 提示
+ 不必为你使用的所有标签都添加元数据。
+
+### 使用你的标签
+
+将 `tags` 参数和*路径操作*(以及 `APIRouter`)一起使用,将其分配给不同的标签:
+
+```Python hl_lines="21 26"
+{!../../../docs_src/metadata/tutorial004.py!}
+```
+
+!!! info
+ Read more about tags in [Path Operation Configuration](../path-operation-configuration/#tags){.internal-link target=_blank}.
+
+### 查看文档
+
+如果你现在查看文档,它们会显示所有附加的元数据:
+
+
+
+### 标签顺序
+
+每个标签元数据字典的顺序也定义了在文档用户界面显示的顺序。
+
+例如按照字母顺序,即使 `users` 排在 `items` 之后,它也会显示在前面,因为我们将它的元数据添加为列表内的第一个字典。
+
+## OpenAPI URL
+
+默认情况下,OpenAPI 模式服务于 `/openapi.json`。
+
+但是你可以通过参数 `openapi_url` 对其进行配置。
+
+例如,将其设置为服务于 `/api/v1/openapi.json`:
+
+```Python hl_lines="3"
+{!../../../docs_src/metadata/tutorial002.py!}
+```
+
+如果你想完全禁用 OpenAPI 模式,可以将其设置为 `openapi_url=None`,这样也会禁用使用它的文档用户界面。
+
+## 文档 URLs
+
+你可以配置两个文档用户界面,包括:
+
+* **Swagger UI**:服务于 `/docs`。
+ * 可以使用参数 `docs_url` 设置它的 URL。
+ * 可以通过设置 `docs_url=None` 禁用它。
+* **Version**:API 版本,例如 `v2` 或者 `2.5.0`。
+ * 可以使用参数 `redoc_url` 设置它的 URL。
+ * 可以通过设置 `redoc_url=None` 禁用它。
+
+例如,设置 Swagger UI 服务于 `/documentation` 并禁用 ReDoc:
+
+```Python hl_lines="3"
+{!../../../docs_src/metadata/tutorial003.py!}
+```
diff --git a/docs/zh/docs/tutorial/middleware.md b/docs/zh/docs/tutorial/middleware.md
index c9a7e7725a120..8be591d8ee697 100644
--- a/docs/zh/docs/tutorial/middleware.md
+++ b/docs/zh/docs/tutorial/middleware.md
@@ -2,7 +2,7 @@
你可以向 **FastAPI** 应用添加中间件.
-"中间件"是一个函数,它在每个**请求**被特定的*路径操作*处理之前,以及在每个**响应**返回之前工作.
+"中间件"是一个函数,它在每个**请求**被特定的*路径操作*处理之前,以及在每个**响应**返回之前工作. And also with every **response** before returning it.
* 它接收你的应用程序的每一个**请求**.
* 然后它可以对这个**请求**做一些事情或者执行任何需要的代码.
@@ -11,7 +11,7 @@
* 它可以对该**响应**做些什么或者执行任何需要的代码.
* 然后它返回这个 **响应**.
-!!! note "技术细节"
+!!! !!! note "技术细节"
如果你使用了 `yield` 关键字依赖, 依赖中的退出代码将在执行中间件*后*执行.
如果有任何后台任务(稍后记录), 它们将在执行中间件*后*运行.
@@ -20,7 +20,7 @@
要创建中间件你可以在函数的顶部使用装饰器 `@app.middleware("http")`.
-中间件参数接收如下参数:
+The middleware function receives:
* `request`.
* 一个函数 `call_next` 它将接收 `request` 作为参数.
@@ -32,15 +32,15 @@
{!../../../docs_src/middleware/tutorial001.py!}
```
-!!! tip
+!!! !!! tip
请记住可以 用'X-' 前缀添加专有自定义请求头.
但是如果你想让浏览器中的客户端看到你的自定义请求头, 你需要把它们加到 CORS 配置 ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) 的 `expose_headers` 参数中,在 Starlette's CORS docs文档中.
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以使用 `from starlette.requests import Request`.
- **FastAPI** 为了开发者方便提供了该对象. 但其实它直接来自于 Starlette.
+ **FastAPI** 为了开发者方便提供了该对象. 但其实它直接来自于 Starlette. But it comes directly from Starlette.
### 在 `response` 的前和后
diff --git a/docs/zh/docs/tutorial/path-operation-configuration.md b/docs/zh/docs/tutorial/path-operation-configuration.md
index f79b0e692d8cd..7102406acc732 100644
--- a/docs/zh/docs/tutorial/path-operation-configuration.md
+++ b/docs/zh/docs/tutorial/path-operation-configuration.md
@@ -2,9 +2,8 @@
*路径操作装饰器*支持多种配置参数。
-!!! warning "警告"
-
- 注意:以下参数应直接传递给**路径操作装饰器**,不能传递给*路径操作函数*。
+!!! warning
+ Notice that these parameters are passed directly to the *path operation decorator*, not to your *path operation function*.
## `status_code` 状态码
@@ -14,71 +13,154 @@
如果记不住数字码的涵义,也可以用 `status` 的快捷常量:
-```Python hl_lines="3 17"
-{!../../../docs_src/path_operation_configuration/tutorial001.py!}
-```
+=== "Python 3.10+"
-状态码在响应中使用,并会被添加到 OpenAPI 概图。
+ ```Python hl_lines="1 15"
+ 注意:以下参数应直接传递给**路径操作装饰器**,不能传递给*路径操作函数*。
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3 17"
+ !!! check "检查"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3 17"
+ API 文档会把该路径操作标记为弃用:
+ ```
-!!! note "技术细节"
+状态码在响应中使用,并会被添加到 OpenAPI 概图。
- 也可以使用 `from starlette import status` 导入状态码。
+!!! 也可以使用 `from starlette import status` 导入状态码。
- **FastAPI** 的`fastapi.status` 和 `starlette.status` 一样,只是快捷方式。实际上,`fastapi.status` 直接继承自 Starlette。
+ **FastAPI** 的`fastapi.status` 和 `starlette.status` 一样,只是快捷方式。 But it comes directly from Starlette.
-## `tags` 参数
+## Tags
`tags` 参数的值是由 `str` 组成的 `list` (一般只有一个 `str` ),`tags` 用于为*路径操作*添加标签:
-```Python hl_lines="17 22 27"
-{!../../../docs_src/path_operation_configuration/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="15 20 25"
+ {!../../../docs_src/path_operation_configuration/tutorial005.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17 22 27"
+ 注意,`response_description` 只用于描述响应,`description` 一般则用于描述*路径操作*。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="17 22 27"
+ {!../../../docs_src/path_operation_configuration/tutorial002.py!}
+ ```
OpenAPI 概图会自动添加标签,供 API 文档接口使用:
-
+
+
+### Tags with Enums
+
+If you have a big application, you might end up accumulating **several tags**, and you would want to make sure you always use the **same tag** for related *path operations*.
-## `summary` 和 `description` 参数
+In these cases, it could make sense to store the tags in an `Enum`.
-路径装饰器还支持 `summary` 和 `description` 这两个参数:
+**FastAPI** supports that the same way as with plain strings:
-```Python hl_lines="20-21"
-{!../../../docs_src/path_operation_configuration/tutorial003.py!}
+```Python hl_lines="1 8-10 13 18"
+{!../../../docs_src/path_operation_configuration/tutorial001.py!}
```
-## 文档字符串(`docstring`)
+## Summary and description
+
+`summary` 和 `description` 参数
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-19"
+ {!../../../docs_src/path_operation_configuration/tutorial003.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="20-21"
+ !!! warning "警告"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20-21"
+ 路径装饰器还支持 summary 和 description 这两个参数:
+ ```
+ 和 description 这两个参数:
+
+
+## Description from docstring
描述内容比较长且占用多行时,可以在函数的 docstring 中声明*路径操作*的描述,**FastAPI** 支持从文档字符串中读取描述内容。
文档字符串支持 Markdown,能正确解析和显示 Markdown 的内容,但要注意文档字符串的缩进。
-```Python hl_lines="19-27"
-{!../../../docs_src/path_operation_configuration/tutorial004.py!}
-```
+=== "Python 3.10+"
-下图为 Markdown 文本在 API 文档中的显示效果:
+ ```Python hl_lines="17-25"
+ {!../../../docs_src/path_operation_configuration/tutorial004.py!}
+ ```
-
+=== "Python 3.9+"
+
+ ```Python hl_lines="19-27"
+ 下图为 Markdown 文本在 API 文档中的显示效果:
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="19-27"
+ 文档字符串(docstring)
+ ```
+)
+
+
+It will be used in the interactive docs:
+
+
## 响应描述
`response_description` 参数用于定义响应的描述说明:
-```Python hl_lines="21"
-{!../../../docs_src/path_operation_configuration/tutorial005.py!}
-```
+=== "Python 3.10+"
-!!! info "说明"
+ ```Python hl_lines="19"
+ !!! info "说明"
+ ```
- 注意,`response_description` 只用于描述响应,`description` 一般则用于描述*路径操作*。
+=== "Python 3.9+"
+
+ ```Python hl_lines="21"
+ !!! note "技术细节"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="21"
+ tags 参数
+ ```
+ 参数
+
-!!! check "检查"
+!!! info
+ Notice that `response_description` refers specifically to the response, the `description` refers to the *path operation* in general.
- OpenAPI 规定每个*路径操作*都要有响应描述。
+!!! OpenAPI 规定每个*路径操作*都要有响应描述。
如果没有定义响应描述,**FastAPI** 则自动生成内容为 "Successful response" 的响应描述。
-
+
## 弃用*路径操作*
@@ -88,14 +170,14 @@ OpenAPI 概图会自动添加标签,供 API 文档接口使用:
{!../../../docs_src/path_operation_configuration/tutorial006.py!}
```
-API 文档会把该路径操作标记为弃用:
+It will be clearly marked as deprecated in the interactive docs:
-
+
下图显示了正常*路径操作*与弃用*路径操作* 的区别:
-
+
-## 小结
+## Recap
通过传递参数给*路径操作装饰器* ,即可轻松地配置*路径操作*、添加元数据。
diff --git a/docs/zh/docs/tutorial/path-params-numeric-validations.md b/docs/zh/docs/tutorial/path-params-numeric-validations.md
index 13512a08edf06..fc045d9b4b3a7 100644
--- a/docs/zh/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/zh/docs/tutorial/path-params-numeric-validations.md
@@ -6,9 +6,48 @@
首先,从 `fastapi` 导入 `Path`:
-```Python hl_lines="1"
-{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ {!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
+ ```
+
+!!! info
+ FastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.
+
+ If you have an older version, you would get errors when trying to use `Annotated`.
+
+ Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} to at least 0.95.1 before using `Annotated`.
## 声明元数据
@@ -16,107 +55,245 @@
例如,要声明路径参数 `item_id`的 `title` 元数据值,你可以输入:
-```Python hl_lines="8"
-{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
!!! note
- 路径参数总是必需的,因为它必须是路径的一部分。
+ A path parameter is always required as it has to be part of the path.
所以,你应该在声明时使用 `...` 将其标记为必需参数。
-
+
然而,即使你使用 `None` 声明路径参数或设置一个其他默认值也不会有任何影响,它依然会是必需参数。
## 按需对参数排序
+!!! tip
+ This is probably not as important or necessary if you use `Annotated`.
+
假设你想要声明一个必需的 `str` 类型查询参数 `q`。
而且你不需要为该参数声明任何其他内容,所以实际上你并不需要使用 `Query`。
-但是你仍然需要使用 `Path` 来声明路径参数 `item_id`。
+But you still need to use `Path` for the `item_id` path parameter. And you don't want to use `Annotated` for some reason.
如果你将带有「默认值」的参数放在没有「默认值」的参数之前,Python 将会报错。
但是你可以对其重新排序,并将不带默认值的值(查询参数 `q`)放到最前面。
-对 **FastAPI** 来说这无关紧要。它将通过参数的名称、类型和默认值声明(`Query`、`Path` 等)来检测参数,而不在乎参数的顺序。
+对 **FastAPI** 来说这无关紧要。 它将通过参数的名称、类型和默认值声明(`Query`、`Path` 等)来检测参数,而不在乎参数的顺序。
因此,你可以将函数声明为:
-```Python hl_lines="7"
-{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
-```
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002.py!}
+ ```
+
+!!! note "技术细节"
+ 当你从 `fastapi` 导入 `Query`、`Path` 和其他同类对象时,它们实际上是函数。
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
+ ```
## 按需对参数排序的技巧
-如果你想不使用 `Query` 声明没有默认值的查询参数 `q`,同时使用 `Path` 声明路径参数 `item_id`,并使它们的顺序与上面不同,Python 对此有一些特殊的语法。
+!!! tip
+ This is probably not as important or necessary if you use `Annotated`.
+
+Here's a **small trick** that can be handy, but you won't need it often.
+
+If you want to:
+
+* !!! info
+ `Query`、`Path` 以及你后面会看到的其他类继承自一个共同的 `Param` 类(不需要直接使用它)。
+* 但是你仍然需要使用 `Path` 来声明路径参数 `item_id`。
+* have them in a different order
+* not use `Annotated`
+
+...Python has a little special syntax for that.
传递 `*` 作为函数的第一个参数。
-Python 不会对该 `*` 做任何事情,但是它将知道之后的所有参数都应作为关键字参数(键值对),也被称为 kwargs,来调用。即使它们没有默认值。
+Python 不会对该 `*` 做任何事情,但是它将知道之后的所有参数都应作为关键字参数(键值对),也被称为 kwargs,来调用。 即使它们没有默认值。
```Python hl_lines="7"
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
+### Better with `Annotated`
+
+Have in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use `*`.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
## 数值校验:大于等于
使用 `Query` 和 `Path`(以及你将在后面看到的其他类)可以声明字符串约束,但也可以声明数值约束。
像下面这样,添加 `ge=1` 后,`item_id` 将必须是一个大于(`g`reater than)或等于(`e`qual)`1` 的整数。
-```Python hl_lines="8"
-{!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004.py!}
+ ```
## 数值校验:大于和小于等于
同样的规则适用于:
* `gt`:大于(`g`reater `t`han)
-* `le`:小于等于(`l`ess than or `e`qual)
+* `ge`:大于等于(`g`reater than or `e`qual)
-```Python hl_lines="9"
-{!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ 总结
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005.py!}
+ ```
## 数值校验:浮点数、大于和小于
数值校验同样适用于 `float` 值。
-能够声明 gt 而不仅仅是 ge 在这个前提下变得重要起来。例如,你可以要求一个值必须大于 `0`,即使它小于 `1`。
+能够声明 gt 而不仅仅是 ge 在这个前提下变得重要起来。 例如,你可以要求一个值必须大于 `0`,即使它小于 `1`。
-因此,`0.5` 将是有效值。但是 `0.0`或 `0` 不是。
+因此,`0.5` 将是有效值。 但是 `0.0`或 `0` 不是。
对于 lt 也是一样的。
-```Python hl_lines="11"
-{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="13"
+ !!! note
+ 路径参数总是必需的,因为它必须是路径的一部分。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ 如果你想不使用 Query 声明没有默认值的查询参数 q,同时使用 Path 声明路径参数 item_id,并使它们的顺序与上面不同,Python 对此有一些特殊的语法。
+ ```
+ 声明没有默认值的查询参数 q,同时使用 Path 声明路径参数 item_id,并使它们的顺序与上面不同,Python 对此有一些特殊的语法。
+
+
+=== "Python 3.6+ non-Annotated"
-## 总结
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial006.py!}
+ ```
+
+## Recap
你能够以与 [查询参数和字符串校验](query-params-str-validations.md){.internal-link target=_blank} 相同的方式使用 `Query`、`Path`(以及其他你还没见过的类)声明元数据和字符串校验。
而且你还可以声明数值校验:
* `gt`:大于(`g`reater `t`han)
-* `ge`:大于等于(`g`reater than or `e`qual)
+* `le`:小于等于(`l`ess than or `e`qual)
* `lt`:小于(`l`ess `t`han)
* `le`:小于等于(`l`ess than or `e`qual)
!!! info
- `Query`、`Path` 以及你后面会看到的其他类继承自一个共同的 `Param` 类(不需要直接使用它)。
+ `Query`, `Path`, and other classes you will see later are subclasses of a common `Param` class.
而且它们都共享相同的所有你已看到并用于添加额外校验和元数据的参数。
-!!! note "技术细节"
- 当你从 `fastapi` 导入 `Query`、`Path` 和其他同类对象时,它们实际上是函数。
+!!! note "Technical Details"
+ When you import `Query`, `Path` and others from `fastapi`, they are actually functions.
当被调用时,它们返回同名类的实例。
-
- 如此,你导入 `Query` 这个函数。当你调用它时,它将返回一个同样命名为 `Query` 的类的实例。
-
+
+ 如此,你导入 `Query` 这个函数。 当你调用它时,它将返回一个同样命名为 `Query` 的类的实例。
+
因为使用了这些函数(而不是直接使用类),所以你的编辑器不会标记有关其类型的错误。
-
+
这样,你可以使用常规的编辑器和编码工具,而不必添加自定义配置来忽略这些错误。
diff --git a/docs/zh/docs/tutorial/path-params.md b/docs/zh/docs/tutorial/path-params.md
index 1b428d6627112..a307010299d68 100644
--- a/docs/zh/docs/tutorial/path-params.md
+++ b/docs/zh/docs/tutorial/path-params.md
@@ -24,7 +24,7 @@
在这个例子中,`item_id` 被声明为 `int` 类型。
-!!! check
+!!! !!! check
这将为你的函数提供编辑器支持,包括错误检查、代码补全等等。
## 数据转换
@@ -35,7 +35,7 @@
{"item_id":3}
```
-!!! check
+!!! !!! check
注意函数接收(并返回)的值为 3,是一个 Python `int` 值,而不是字符串 `"3"`。
所以,**FastAPI** 通过上面的类型声明提供了对请求的自动"解析"。
@@ -63,20 +63,20 @@
如果你提供的是 `float` 而非整数也会出现同样的错误,比如: http://127.0.0.1:8000/items/4.2
-!!! check
+!!! !!! check
所以,通过同样的 Python 类型声明,**FastAPI** 提供了数据校验功能。
注意上面的错误同样清楚地指出了校验未通过的具体原因。
-
+
在开发和调试与你的 API 进行交互的代码时,这非常有用。
## 文档
当你打开浏览器访问 http://127.0.0.1:8000/docs,你将看到自动生成的交互式 API 文档:
-
+
-!!! check
+!!! !!! check
再一次,还是通过相同的 Python 类型声明,**FastAPI** 为你提供了自动生成的交互式文档(集成 Swagger UI)。
注意这里的路径参数被声明为一个整数。
@@ -87,19 +87,19 @@
正因如此,**FastAPI** 内置了一个可选的 API 文档(使用 Redoc):
-
+
-同样的,还有很多其他兼容的工具,包括适用于多种语言的代码生成工具。
+The same way, there are many compatible tools. 同样的,还有很多其他兼容的工具,包括适用于多种语言的代码生成工具。
## Pydantic
-所有的数据校验都由 Pydantic 在幕后完成,所以你可以从它所有的优点中受益。并且你知道它在这方面非常胜任。
+所有的数据校验都由 Pydantic 在幕后完成,所以你可以从它所有的优点中受益。 并且你知道它在这方面非常胜任。
你可以使用同样的类型声明来声明 `str`、`float`、`bool` 以及许多其他的复合数据类型。
本教程的下一章节将探讨其中的一些内容。
-## 顺序很重要
+## Order matters
在创建*路径操作*时,你会发现有些情况下路径是固定的。
@@ -108,12 +108,21 @@
然后,你还可以使用路径 `/users/{user_id}` 来通过用户 ID 获取关于特定用户的数据。
由于*路径操作*是按顺序依次运行的,你需要确保路径 `/users/me` 声明在路径 `/users/{user_id}`之前:
+
```Python hl_lines="6 11"
{!../../../docs_src/path_params/tutorial003.py!}
```
否则,`/users/{user_id}` 的路径还将与 `/users/me` 相匹配,"认为"自己正在接收一个值为 `"me"` 的 `user_id` 参数。
+Similarly, you cannot redefine a path operation:
+
+```Python hl_lines="6 11"
+{!../../../docs_src/path_params/tutorial003b.py!}
+```
+
+The first one will always be used since the path matches first.
+
## 预设值
如果你有一个接收路径参数的路径操作,但你希望预先设定可能的有效参数值,则可以使用标准的 Python `Enum` 类型。
@@ -130,10 +139,10 @@
{!../../../docs_src/path_params/tutorial005.py!}
```
-!!! info
+!!! !!! info
枚举(或 enums)从 3.4 版本起在 Python 中可用。
-!!! tip
+!!! !!! tip
如果你想知道,"AlexNet"、"ResNet" 和 "LeNet" 只是机器学习中的模型名称。
### 声明*路径参数*
@@ -146,13 +155,13 @@
### 查看文档
-因为已经指定了*路径参数*的可用值,所以交互式文档可以恰当地展示它们:
+*路径参数*的值将是一个*枚举成员*。
-
+
### 使用 Python *枚举类型*
-*路径参数*的值将是一个*枚举成员*。
+因为已经指定了*路径参数*的可用值,所以交互式文档可以恰当地展示它们:
#### 比较*枚举成员*
@@ -166,11 +175,11 @@
你可以使用 `model_name.value` 或通常来说 `your_enum_member.value` 来获取实际的值(在这个例子中为 `str`):
-```Python hl_lines="19"
+```Python hl_lines="20"
{!../../../docs_src/path_params/tutorial005.py!}
```
-!!! tip
+!!! !!! tip
你也可以通过 `ModelName.lenet.value` 来获取值 `"lenet"`。
#### 返回*枚举成员*
@@ -179,10 +188,19 @@
在返回给客户端之前,它们将被转换为对应的值:
-```Python hl_lines="18-21"
+```Python hl_lines="18 21 23"
{!../../../docs_src/path_params/tutorial005.py!}
```
+In your client you will get a JSON response like:
+
+```JSON
+{
+ "model_name": "alexnet",
+ "message": "Deep Learning FTW!"
+}
+```
+
## 包含路径的路径参数
假设你有一个*路径操作*,它的路径为 `/files/{file_path}`。
@@ -193,7 +211,7 @@
### OpenAPI 支持
-OpenAPI 不支持任何方式去声明*路径参数*以在其内部包含*路径*,因为这可能会导致难以测试和定义的情况出现。
+你可以使用直接来自 Starlette 的选项来声明一个包含*路径*的*路径参数*:
不过,你仍然可以通过 Starlette 的一个内部工具在 **FastAPI** 中实现它。
@@ -201,7 +219,7 @@ OpenAPI 不支持任何方式去声明*路径参数*以在其内部包含*路径
### 路径转换器
-你可以使用直接来自 Starlette 的选项来声明一个包含*路径*的*路径参数*:
+OpenAPI 不支持任何方式去声明*路径参数*以在其内部包含*路径*,因为这可能会导致难以测试和定义的情况出现。
```
/files/{file_path:path}
@@ -215,12 +233,12 @@ OpenAPI 不支持任何方式去声明*路径参数*以在其内部包含*路径
{!../../../docs_src/path_params/tutorial004.py!}
```
-!!! tip
+!!! !!! tip
你可能会需要参数包含 `/home/johndoe/myfile.txt`,以斜杠(`/`)开头。
在这种情况下,URL 将会是 `/files//home/johndoe/myfile.txt`,在`files` 和 `home` 之间有一个双斜杠(`//`)。
-## 总结
+## Recap
使用 **FastAPI**,通过简短、直观和标准的 Python 类型声明,你将获得:
diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md
index 070074839f634..15ef418f38a1c 100644
--- a/docs/zh/docs/tutorial/query-params-str-validations.md
+++ b/docs/zh/docs/tutorial/query-params-str-validations.md
@@ -4,11 +4,25 @@
让我们以下面的应用程序为例:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
-查询参数 `q` 的类型为 `str`,默认值为 `None`,因此它是可选的。
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
+ ```
+
+!!! note
+ 请记住,在这种情况下 FastAPI 将不会检查列表的内容。
+
+!!! note
+ FastAPI will know that the value of `q` is not required because of the default value `= None`.
+
+ The `Union` in `Union[str, None]` will allow your editor to give you better support and detect errors.
## 额外的校验
@@ -16,19 +30,122 @@
### 导入 `Query`
-为此,首先从 `fastapi` 导入 `Query`:
+To achieve that, first import:
-```Python hl_lines="1"
-{!../../../docs_src/query_params_str_validations/tutorial002.py!}
-```
+* 为此,首先从 `fastapi` 导入 `Query`:
+* `Annotated` from `typing` (or from `typing_extensions` in Python below 3.9)
+
+=== "Python 3.10+"
+
+ In Python 3.9 or above, `Annotated` is part of the standard library, so you can import it from `typing`.
+
+ ```Python hl_lines="1 3"
+ {!../../../docs_src/query_params_str_validations/tutorial002.py!}
+ ```
+
+=== "Python 3.6+"
+
+ In versions of Python below Python 3.9 you import `Annotated` from `typing_extensions`.
+
+ It will already be installed with FastAPI.
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
+ ```
+
+!!! info
+ FastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.
+
+ If you have an older version, you would get errors when trying to use `Annotated`.
+
+ Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} to at least 0.95.1 before using `Annotated`.
+
+## !!! tip
+ 要声明类型为 `list` 的查询参数,如上例所示,你需要显式地使用 `Query`,否则该参数将被解释为请求体。
+
+Remember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+
+Now it's the time to use it with FastAPI. 🚀
+
+We had this type annotation:
+
+=== "Python 3.10+"
+
+ ```Python
+ q: str | None = None
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Union[str, None] = None
+ ```
+
+What we will do is wrap that with `Annotated`, so it becomes:
+
+=== "Python 3.10+"
+
+ ```Python
+ 总结
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Annotated[Union[str, None]] = None
+ ```
+
+查询参数 `q` 的类型为 `str`,默认值为 `None`,因此它是可选的。
+
+Now let's jump to the fun stuff. 🎉
+
+## 但是 `Query` 显式地将其声明为查询参数。
+
+Now that we have this `Annotated` where we can put more metadata, add `Query` to it, and set the parameter `max_length` to 50:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!../../../docs_src/query_params_str_validations/tutorial006d.py!}
+ ```
+
+!!! note
+ 具有默认值还会使该参数成为可选参数。
+
+But now, having `Query(max_length=50)` inside of `Annotated`, we are telling FastAPI that we want it to extract this value from the query parameters (this would have been the default anyway 🤷) and that we want to have **additional validation** for this value (that's why we do this, to get the additional validation). 😎
+
+FastAPI will now:
+
+* **Validate** the data making sure that the max length is 50 characters
+* Show a **clear error** for the client when the data is not valid
+* **Document** the parameter in the OpenAPI schema *path operation* (so it will show up in the **automatic docs UI**)
-## 使用 `Query` 作为默认值
+## 你可以向 `Query` 的第一个参数传入 `None` 用作查询参数的默认值,以同样的方式你也可以传递其他默认值。
+
+Previous versions of FastAPI (before 0.95.0) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.
+
+!!! tip
+ For new code and whenever possible, use `Annotated` as explained above. There are multiple advantages (explained below) and no disadvantages. 🍰
现在,将 `Query` 用作查询参数的默认值,并将它的 `max_length` 参数设置为 50:
-```Python hl_lines="9"
-{!../../../docs_src/query_params_str_validations/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params_str_validations/tutorial002.py!}
+ ```
由于我们必须用 `Query(default=None)` 替换默认值 `None`,`Query` 的第一个参数同样也是用于定义默认值。
@@ -40,13 +157,44 @@ q: Union[str, None] = Query(default=None)
...使得参数可选,等同于:
+```Python
+q: Union[str, None] = None
+```
+
+And in Python 3.10 and above:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+有另一种方法可以显式的声明一个值是必需的,即将默认参数的默认值设为 `...` :
+
```Python
q: str = None
```
-但是 `Query` 显式地将其声明为查询参数。
+声明为必需参数
+
+!!! info
+ Have in mind that the most important part to make a parameter optional is the part:
+
+ ```Python
+ = None
+ ```
+
-然后,我们可以将更多的参数传递给 `Query`。在本例中,适用于字符串的 `max_length` 参数:
+ or the:
+
+ ```Python
+ = Query(default=None)
+ ```
+
+
+ as it will use that `None` as the default value, and that way make the parameter **not required**.
+
+ The `Union[str, None]` part allows your editor to provide better support, but it is not what tells FastAPI that this parameter is not required.
+
+然后,我们可以将更多的参数传递给 `Query`。 在本例中,适用于字符串的 `max_length` 参数:
```Python
q: Union[str, None] = Query(default=None, max_length=50)
@@ -54,21 +202,124 @@ q: Union[str, None] = Query(default=None, max_length=50)
将会校验数据,在数据无效时展示清晰的错误信息,并在 OpenAPI 模式的*路径操作*中记录该参数。
+### 使用 `Query` 作为默认值
+
+!!! tip
+ 请记住,在大多数情况下,当你需要某些东西时,可以简单地省略 `default` 参数,因此你通常不必使用 `...` 或 `Required`
+
+Instead use the actual default value of the function parameter. Otherwise, it would be inconsistent.
+
+For example, this is not allowed:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...because it's not clear if the default value should be `"rick"` or `"morty"`.
+
+So, you would use (preferably):
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...or in older code bases you will find:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### Advantages of `Annotated`
+
+**Using `Annotated` is recommended** instead of the default value in function parameters, it is **better** for multiple reasons. 🤓
+
+The **default** value of the **function parameter** is the **actual default** value, that's more intuitive with Python in general. 😌
+
+You could **call** that same function in **other places** without FastAPI, and it would **work as expected**. If there's a **required** parameter (without a default value), your **editor** will let you know with an error, **Python** will also complain if you run it without passing the required parameter.
+
+When you don't use `Annotated` and instead use the **(old) default value style**, if you call that function without FastAPI in **other place**, you have to **remember** to pass the arguments to the function for it to work correctly, otherwise the values will be different from what you expect (e.g. `QueryInfo` or something similar instead of `str`). And your editor won't complain, and Python won't complain running that function, only when the operations inside error out.
+
+Because `Annotated` can have more than one metadata annotation, you could now even use the same function with other tools, like Typer. 🚀
+
## 添加更多校验
你还可以添加 `min_length` 参数:
-```Python hl_lines="10"
-{!../../../docs_src/query_params_str_validations/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!../../../docs_src/query_params_str_validations/tutorial003.py!}
+ ```
## 添加正则表达式
你可以定义一个参数值必须匹配的正则表达式:
-```Python hl_lines="11"
-{!../../../docs_src/query_params_str_validations/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params_str_validations/tutorial013.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
+ {!../../../docs_src/query_params_str_validations/tutorial004.py!}
+ ```
这个指定的正则表达式通过以下规则检查接收到的参数值:
@@ -76,24 +327,56 @@ q: Union[str, None] = Query(default=None, max_length=50)
* `fixedquery`: 值精确地等于 `fixedquery`。
* `$`: 到此结束,在 `fixedquery` 之后没有更多字符。
-如果你对所有的这些**「正则表达式」**概念感到迷茫,请不要担心。对于许多人来说这都是一个困难的主题。你仍然可以在无需正则表达式的情况下做很多事情。
+如果你对所有的这些**「正则表达式」**概念感到迷茫,请不要担心。 对于许多人来说这都是一个困难的主题。 你仍然可以在无需正则表达式的情况下做很多事情。
但是,一旦你需要用到并去学习它们时,请了解你已经可以在 **FastAPI** 中直接使用它们。
+### Pydantic v1 `regex` instead of `pattern`
+
+Before Pydantic version 2 and before FastAPI 0.100.0, the parameter was called `regex` instead of `pattern`, but it's now deprecated.
+
+You could still see some code using it:
+
+=== "Python 3.10+ Pydantic v1"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310_regex.py!}
+ ```
+
+But know that this is deprecated and it should be updated to use the new parameter `pattern`. 🤓
+
## 默认值
-你可以向 `Query` 的第一个参数传入 `None` 用作查询参数的默认值,以同样的方式你也可以传递其他默认值。
+!!! note
+ 请记住,不同的工具对 OpenAPI 的支持程度可能不同。
假设你想要声明查询参数 `q`,使其 `min_length` 为 `3`,并且默认值为 `fixedquery`:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!../../../docs_src/query_params_str_validations/tutorial005.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/query_params_str_validations/tutorial008.py!}
+ ```
!!! note
- 具有默认值还会使该参数成为可选参数。
+ Having a default value of any type, including `None`, makes the parameter optional (not required).
-## 声明为必需参数
+## Make it required
当我们不需要声明额外的校验或元数据时,只需不声明默认值就可以使 `q` 参数成为必需参数,例如:
@@ -109,54 +392,151 @@ q: Union[str, None] = None
但是现在我们正在用 `Query` 声明它,例如:
-```Python
-q: Union[str, None] = Query(default=None, min_length=3)
-```
+=== "Annotated"
+
+ ```Python
+ q: Annotated[Union[str, None], Query(min_length=3)] = None
+ ```
+
+=== "non-Annotated"
+
+ ```Python
+ q: Union[str, None] = Query(default=None, min_length=3)
+ ```
因此,当你在使用 `Query` 且需要声明一个值是必需的时,只需不声明默认参数:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/query_params_str_validations/tutorial006.py!}
+ ```
+
+
+ !!! tip
+ Notice that, even though in this case the `Query()` is used as the function parameter default value, we don't pass the `default=None` to `Query()`.
+
+ Still, probably better to use the `Annotated` version. 😉
### 使用省略号(`...`)声明必需参数
-有另一种方法可以显式的声明一个值是必需的,即将默认参数的默认值设为 `...` :
+There's an alternative way to explicitly declare that a value is required. You can set the default to the literal value `...`:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial006b.py!}
-```
+=== "Python 3.9+"
-!!! info
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/query_params_str_validations/tutorial006b.py!}
+ ```
+
+!!! !!! info
如果你之前没见过 `...` 这种用法:它是一个特殊的单独值,它是 Python 的一部分并且被称为「省略号」。
+
Pydantic 和 FastAPI 使用它来显式的声明需要一个值。
这将使 **FastAPI** 知道此查询参数是必需的。
### 使用`None`声明必需参数
-你可以声明一个参数可以接收`None`值,但它仍然是必需的。这将强制客户端发送一个值,即使该值是`None`。
+你可以声明一个参数可以接收`None`值,但它仍然是必需的。 这将强制客户端发送一个值,即使该值是`None`。
为此,你可以声明`None`是一个有效的类型,并仍然使用`default=...`:
-```Python hl_lines="9"
-{!../../../docs_src/query_params_str_validations/tutorial006c.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ ```
!!! tip
- Pydantic 是 FastAPI 中所有数据验证和序列化的核心,当你在没有设默认值的情况下使用 `Optional` 或 `Union[Something, None]` 时,它具有特殊行为,你可以在 Pydantic 文档中阅读有关必需可选字段的更多信息。
+ Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields.
### 使用Pydantic中的`Required`代替省略号(`...`)
如果你觉得使用 `...` 不舒服,你也可以从 Pydantic 导入并使用 `Required`:
-```Python hl_lines="2 8"
-{!../../../docs_src/query_params_str_validations/tutorial006d.py!}
-```
+=== "Python 3.9+"
-!!! tip
- 请记住,在大多数情况下,当你需要某些东西时,可以简单地省略 `default` 参数,因此你通常不必使用 `...` 或 `Required`
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="2 9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d.py!}
+ ```
+
+!!! tip
+ Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...` nor `Required`.
## 查询参数列表 / 多个值
@@ -164,9 +544,53 @@ q: Union[str, None] = Query(default=None, min_length=3)
例如,要声明一个可在 URL 中出现多次的查询参数 `q`,你可以这样写:
-```Python hl_lines="9"
-{!../../../docs_src/query_params_str_validations/tutorial011.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ !!! tip
+ Pydantic 是 FastAPI 中所有数据验证和序列化的核心,当你在没有设默认值的情况下使用 Optional 或 Union[Something, None] 时,它具有特殊行为,你可以在 Pydantic 文档中阅读有关必需可选字段的更多信息。
+ ```
+ 或 Union[Something, None] 时,它具有特殊行为,你可以在 Pydantic 文档中阅读有关必需可选字段的更多信息。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params_str_validations/tutorial011.py!}
+ ```
然后,输入如下网址:
@@ -188,19 +612,45 @@ http://localhost:8000/items/?q=foo&q=bar
```
!!! tip
- 要声明类型为 `list` 的查询参数,如上例所示,你需要显式地使用 `Query`,否则该参数将被解释为请求体。
+ To declare a query parameter with a type of `list`, like in the example above, you need to explicitly use `Query`, otherwise it would be interpreted as a request body.
交互式 API 文档将会相应地进行更新,以允许使用多个值:
-
+
### 具有默认值的查询参数列表 / 多个值
你还可以定义在没有任何给定值时的默认 `list` 值:
-```Python hl_lines="9"
-{!../../../docs_src/query_params_str_validations/tutorial012.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params_str_validations/tutorial012.py!}
+ ```
如果你访问:
@@ -223,14 +673,31 @@ http://localhost:8000/items/
你也可以直接使用 `list` 代替 `List [str]`:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial013.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013.py!}
+ ```
!!! note
- 请记住,在这种情况下 FastAPI 将不会检查列表的内容。
+ Have in mind that in this case, FastAPI won't check the contents of the list.
- 例如,`List[int]` 将检查(并记录到文档)列表的内容必须是整数。但是单独的 `list` 不会。
+ 例如,`List[int]` 将检查(并记录到文档)列表的内容必须是整数。 但是单独的 `list` 不会。
## 声明更多元数据
@@ -239,21 +706,85 @@ http://localhost:8000/items/
这些信息将包含在生成的 OpenAPI 模式中,并由文档用户界面和外部工具所使用。
!!! note
- 请记住,不同的工具对 OpenAPI 的支持程度可能不同。
+ Have in mind that different tools might have different levels of OpenAPI support.
其中一些可能不会展示所有已声明的额外信息,尽管在大多数情况下,缺少的这部分功能已经计划进行开发。
你可以添加 `title`:
-```Python hl_lines="10"
-{!../../../docs_src/query_params_str_validations/tutorial007.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!../../../docs_src/query_params_str_validations/tutorial007.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
+ ```
以及 `description`:
-```Python hl_lines="13"
-{!../../../docs_src/query_params_str_validations/tutorial008.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="13"
+ {!../../../docs_src/query_params_str_validations/tutorial001.py!}
+ ```
## 别名参数
@@ -273,9 +804,41 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
这时你可以用 `alias` 参数声明一个别名,该别名将用于在 URL 中查找查询参数值:
-```Python hl_lines="9"
-{!../../../docs_src/query_params_str_validations/tutorial009.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params_str_validations/tutorial009.py!}
+ ```
## 弃用参数
@@ -285,15 +848,87 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
那么将参数 `deprecated=True` 传入 `Query`:
-```Python hl_lines="18"
-{!../../../docs_src/query_params_str_validations/tutorial010.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="18"
+ {!../../../docs_src/query_params_str_validations/tutorial010.py!}
+ ```
文档将会像下面这样展示它:
-
+
+
+## Exclude from OpenAPI
+
+To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
+ ```
-## 总结
+## Recap
你可以为查询参数声明额外的校验和元数据。
diff --git a/docs/zh/docs/tutorial/query-params.md b/docs/zh/docs/tutorial/query-params.md
index b1668a2d2523f..dead131d45f8e 100644
--- a/docs/zh/docs/tutorial/query-params.md
+++ b/docs/zh/docs/tutorial/query-params.md
@@ -6,7 +6,7 @@
{!../../../docs_src/query_params/tutorial001.py!}
```
-查询字符串是键值对的集合,这些键值对位于 URL 的 `?` 之后,并以 `&` 符号分隔。
+查询字符串是键值对的集合,这些键值对位于 URL 的 `? ` 之后,并以 `&` 符号分隔。
例如,在以下 url 中:
@@ -42,7 +42,7 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
http://127.0.0.1:8000/items/
```
-将与访问以下地址相同:
+would be the same as going to:
```
http://127.0.0.1:8000/items/?skip=0&limit=10
@@ -63,22 +63,41 @@ http://127.0.0.1:8000/items/?skip=20
通过同样的方式,你可以将它们的默认值设置为 `None` 来声明可选查询参数:
-```Python hl_lines="7"
-{!../../../docs_src/query_params/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ 将与访问以下地址相同:
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!../../../docs_src/query_params/tutorial002.py!}
+ ```
在这个例子中,函数参数 `q` 将是可选的,并且默认值为 `None`。
!!! check
- 还要注意的是,**FastAPI** 足够聪明,能够分辨出参数 `item_id` 是路径参数而 `q` 不是,因此 `q` 是一个查询参数。
+ Also notice that **FastAPI** is smart enough to notice that the path parameter `item_id` is a path parameter and `q` is not, so, it's a query parameter.
## 查询参数类型转换
你还可以声明 `bool` 类型,它们将被自动转换:
-```Python hl_lines="7"
-{!../../../docs_src/query_params/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/query_params/tutorial003.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ !!! check
+ 还要注意的是,FastAPI 足够聪明,能够分辨出参数 item_id 是路径参数而 q 不是,因此 q 是一个查询参数。
+ ```
+ 是路径参数而 q 不是,因此 q 是一个查询参数。
+
这个例子中,如果你访问:
@@ -110,7 +129,7 @@ http://127.0.0.1:8000/items/foo?short=on
http://127.0.0.1:8000/items/foo?short=yes
```
-或任何其他的变体形式(大写,首字母大写等等),你的函数接收的 `short` 参数都会是布尔值 `True`。对于值为 `False` 的情况也是一样的。
+或任何其他的变体形式(大写,首字母大写等等),你的函数接收的 `short` 参数都会是布尔值 `True`。 对于值为 `False` 的情况也是一样的。
## 多个路径和查询参数
@@ -121,9 +140,17 @@ http://127.0.0.1:8000/items/foo?short=yes
它们将通过名称被检测到:
-```Python hl_lines="6 8"
-{!../../../docs_src/query_params/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="6 8"
+ {!> ../../../docs_src/query_params/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8 10"
+ {!../../../docs_src/query_params/tutorial004.py!}
+ ```
## 必需查询参数
@@ -179,9 +206,20 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
当然,你也可以定义一些参数为必需的,一些具有默认值,而某些则完全是可选的:
-```Python hl_lines="7"
-{!../../../docs_src/query_params/tutorial006.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="8"
+ {!../../../docs_src/query_params/tutorial006.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ !!! tip
+ 你还可以像在 路径参数{.internal-link target=_blank} 中那样使用 Enum。
+ ```
+。
+
在这个例子中,有3个查询参数:
@@ -190,4 +228,4 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
* `limit`,一个可选的 `int` 类型参数。
!!! tip
- 你还可以像在 [路径参数](path-params.md#predefined-values){.internal-link target=_blank} 中那样使用 `Enum`。
+ You could also use `Enum`s the same way as with [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}.
diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md
index 03474907ee94b..cf5d05139c827 100644
--- a/docs/zh/docs/tutorial/request-files.md
+++ b/docs/zh/docs/tutorial/request-files.md
@@ -2,45 +2,75 @@
`File` 用于定义客户端的上传文件。
-!!! info "说明"
+!!! info
+ To receive uploaded files, first install `python-multipart`.
+ E.g. 例如: `pip install python-multipart`。
+
因为上传文件以「表单数据」形式发送。
- 所以接收上传文件,要预先安装 `python-multipart`。
-
- 例如: `pip install python-multipart`。
-
## 导入 `File`
从 `fastapi` 导入 `File` 和 `UploadFile`:
-```Python hl_lines="1"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ !!! info "说明"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ FastAPI 支持同时上传多个文件。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/request_files/tutorial001.py!}
+ ```
## 定义 `File` 参数
创建文件(`File`)参数的方式与 `Body` 和 `Form` 一样:
-```Python hl_lines="7"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
-!!! info "说明"
+ ```Python hl_lines="9"
+ !!! info "说明"
+ ```
- `File` 是直接继承自 `Form` 的类。
+=== "Python 3.6+"
- 注意,从 `fastapi` 导入的 `Query`、`Path`、`File` 等项,实际上是返回特定类的函数。
+ ```Python hl_lines="8"
+ 使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `await` 操作完成。
+ ```
-!!! tip "提示"
+=== "Python 3.6+ non-Annotated"
- 声明文件体必须使用 `File`,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/request_files/tutorial001.py!}
+ ```
+
+!!! `File` 是直接继承自 `Form` 的类。
+
+ 注意,从 `fastapi` 导入的 `Query`、`Path`、`File` 等项,实际上是返回特定类的函数。
+
+!!! tip
+ To declare File bodies, you need to use `File`, because otherwise the parameters would be interpreted as query parameters or body (JSON) parameters.
文件作为「表单数据」上传。
如果把*路径操作函数*参数的类型声明为 `bytes`,**FastAPI** 将以 `bytes` 形式读取和接收文件内容。
-这种方式把文件的所有内容都存储在内存里,适用于小型文件。
+Have in mind that this means that the whole contents will be stored in memory. This will work well for small files.
不过,很多情况下,`UploadFile` 更好用。
@@ -48,18 +78,36 @@
定义文件参数时使用 `UploadFile`:
-```Python hl_lines="12"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ !!! note "技术细节"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="13"
+ 声明文件体必须使用 `File`,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="12"
+ {!../../../docs_src/request_files/tutorial001.py!}
+ ```
`UploadFile` 与 `bytes` 相比有更多优势:
+* 本节介绍了如何用 `File` 把上传文件声明为(表单数据的)输入参数。
* 使用 `spooled` 文件:
* 存储在内存的文件超出最大上限时,FastAPI 会把文件存入磁盘;
* 这种方式更适于处理图像、视频、二进制文件等大型文件,好处是不会占用所有内存;
* 可获取上传文件的元数据;
-* 自带 file-like `async` 接口;
* 暴露的 Python `SpooledTemporaryFile` 对象,可直接传递给其他预期「file-like」对象的库。
+* 自带 file-like `async` 接口;
### `UploadFile`
@@ -67,14 +115,14 @@
* `filename`:上传文件名字符串(`str`),例如, `myimage.jpg`;
* `content_type`:内容类型(MIME 类型 / 媒体类型)字符串(`str`),例如,`image/jpeg`;
-* `file`: `SpooledTemporaryFile`( file-like 对象)。其实就是 Python文件,可直接传递给其他预期 `file-like` 对象的函数或支持库。
+* `file`: `SpooledTemporaryFile`( file-like 对象)。 其实就是 Python文件,可直接传递给其他预期 `file-like` 对象的函数或支持库。
-`UploadFile` 支持以下 `async` 方法,(使用内部 `SpooledTemporaryFile`)可调用相应的文件方法。
+`UploadFile` has the following `async` methods. They all call the corresponding file methods underneath (using the internal `SpooledTemporaryFile`).
* `write(data)`:把 `data` (`str` 或 `bytes`)写入文件;
* `read(size)`:按指定数量的字节或字符(`size` (`int`))读取文件内容;
* `seek(offset)`:移动至文件 `offset` (`int`)字节处的位置;
- * 例如,`await myfile.seek(0) ` 移动到文件开头;
+ * 例如,`await myfile.seek(0)` 移动到文件开头;
* 执行 `await myfile.read()` 后,需再次读取已读取内容时,这种方法特别好用;
* `close()`:关闭文件。
@@ -92,13 +140,10 @@ contents = await myfile.read()
contents = myfile.file.read()
```
-!!! note "`async` 技术细节"
-
- 使用 `async` 方法时,**FastAPI** 在线程池中执行文件方法,并 `await` 操作完成。
-
-!!! note "Starlette 技术细节"
+!!! note "`async` Technical Details" When you use the `async` methods, **FastAPI** runs the file methods in a threadpool and awaits for them.
- **FastAPI** 的 `UploadFile` 直接继承自 **Starlette** 的 `UploadFile`,但添加了一些必要功能,使之与 **Pydantic** 及 FastAPI 的其它部件兼容。
+!!! note "Starlette Technical Details"
+ **FastAPI**'s `UploadFile` inherits directly from **Starlette**'s `UploadFile`, but adds some necessary parts to make it compatible with **Pydantic** and the other parts of FastAPI.
## 什么是 「表单数据」
@@ -106,17 +151,13 @@ contents = myfile.file.read()
**FastAPI** 要确保从正确的位置读取数据,而不是读取 JSON。
-!!! note "技术细节"
-
- 不包含文件时,表单数据一般用 `application/x-www-form-urlencoded`「媒体类型」编码。
-
- 但表单包含文件时,编码为 `multipart/form-data`。使用了 `File`,**FastAPI** 就知道要从请求体的正确位置获取文件。
+!!! 不包含文件时,表单数据一般用 `application/x-www-form-urlencoded`「媒体类型」编码。
+ 但表单包含文件时,编码为 `multipart/form-data`。 使用了 `File`,**FastAPI** 就知道要从请求体的正确位置获取文件。
+
编码和表单字段详见 MDN Web 文档的 POST 小节。
-!!! warning "警告"
-
- 可在一个*路径操作*中声明多个 `File` 和 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码是 `multipart/form-data`,不是 `application/json`。
+!!! 可在一个*路径操作*中声明多个 `File` 和 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。 因为此时请求体的编码是 `multipart/form-data`,不是 `application/json`。
这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。
@@ -124,14 +165,40 @@ contents = myfile.file.read()
您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选:
+=== "Python 3.10+"
+
+ ```Python hl_lines="9 17"
+ 这种方式把文件的所有内容都存储在内存里,适用于小型文件。
+ ```
+
=== "Python 3.9+"
- ```Python hl_lines="7 14"
- {!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
+ ```Python hl_lines="9 17"
+ !!! warning "警告"
```
=== "Python 3.6+"
+ ```Python hl_lines="10 18"
+ !!! note "async 技术细节"
+ ```
+ 技术细节"
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 15"
+ {!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="9 17"
{!> ../../../docs_src/request_files/tutorial001_02.py!}
```
@@ -140,25 +207,62 @@ contents = myfile.file.read()
您也可以将 `File()` 与 `UploadFile` 一起使用,例如,设置额外的元数据:
-```Python hl_lines="13"
-{!../../../docs_src/request_files/tutorial001_03.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9 15"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8 14"
+ **FastAPI** 的 `UploadFile` 直接继承自 **Starlette** 的 `UploadFile`,但添加了一些必要功能,使之与 **Pydantic** 及 FastAPI 的其它部件兼容。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 13"
+ 可用同一个「表单字段」发送含多个文件的「表单数据」。
+ ```
## 多文件上传
-FastAPI 支持同时上传多个文件。
+It's possible to upload several files at the same time.
-可用同一个「表单字段」发送含多个文件的「表单数据」。
+They would be associated to the same "form field" sent using "form data".
上传多个文件时,要声明含 `bytes` 或 `UploadFile` 的列表(`List`):
=== "Python 3.9+"
+ ```Python hl_lines="10 15"
+ !!! note "Starlette 技术细节"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11 16"
+ UploadFile 支持以下 async 方法,(使用内部 SpooledTemporaryFile)可调用相应的文件方法。
+ ```
+ 支持以下 async 方法,(使用内部 SpooledTemporaryFile)可调用相应的文件方法。
+
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
```Python hl_lines="8 13"
{!> ../../../docs_src/request_files/tutorial002_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="10 15"
{!> ../../../docs_src/request_files/tutorial002.py!}
@@ -166,12 +270,9 @@ FastAPI 支持同时上传多个文件。
接收的也是含 `bytes` 或 `UploadFile` 的列表(`list`)。
+!!! 也可以使用 `from starlette.responses import HTMLResponse`。
-!!! note "技术细节"
-
- 也可以使用 `from starlette.responses import HTMLResponse`。
-
- `fastapi.responses` 其实与 `starlette.responses` 相同,只是为了方便开发者调用。实际上,大多数 **FastAPI** 的响应都直接从 Starlette 调用。
+ `fastapi.responses` 其实与 `starlette.responses` 相同,只是为了方便开发者调用。 实际上,大多数 **FastAPI** 的响应都直接从 Starlette 调用。 But most of the available responses come directly from Starlette.
### 带有额外元数据的多文件上传
@@ -179,16 +280,34 @@ FastAPI 支持同时上传多个文件。
=== "Python 3.9+"
- ```Python hl_lines="16"
- {!> ../../../docs_src/request_files/tutorial003_py39.py!}
+ ```Python hl_lines="11 18-20"
+ !!! note "技术细节"
```
=== "Python 3.6+"
- ```Python hl_lines="18"
+ ```Python hl_lines="12 19-21"
+ {!../../../docs_src/request_files/tutorial001_03.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9 16"
+ {!> ../../../docs_src/request_files/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11 18"
{!> ../../../docs_src/request_files/tutorial003.py!}
```
-## 小结
+## Recap
-本节介绍了如何用 `File` 把上传文件声明为(表单数据的)输入参数。
+Use `File`, `bytes`, and `UploadFile` to declare files to be uploaded in the request, sent as form data.
diff --git a/docs/zh/docs/tutorial/request-forms-and-files.md b/docs/zh/docs/tutorial/request-forms-and-files.md
index 70cd70f98650c..6dc779760bfbf 100644
--- a/docs/zh/docs/tutorial/request-forms-and-files.md
+++ b/docs/zh/docs/tutorial/request-forms-and-files.md
@@ -2,36 +2,66 @@
FastAPI 支持同时使用 `File` 和 `Form` 定义文件和表单字段。
-!!! info "说明"
+!!! 接收上传文件或表单数据,要预先安装 <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>。
- 接收上传文件或表单数据,要预先安装 `python-multipart`。
-
- 例如,`pip install python-multipart`。
+ E.g. 例如,`pip install python-multipart`。
## 导入 `File` 与 `Form`
-```Python hl_lines="1"
-{!../../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ !!! warning "警告"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/request_forms_and_files/tutorial001.py!}
+ ```
## 定义 `File` 与 `Form` 参数
创建文件和表单参数的方式与 `Body` 和 `Query` 一样:
-```Python hl_lines="8"
-{!../../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10-12"
+ 小结
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-11"
+ !!! info "说明"
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!../../../docs_src/request_forms_and_files/tutorial001.py!}
+ ```
文件和表单字段作为表单数据上传与接收。
声明文件可以使用 `bytes` 或 `UploadFile` 。
-!!! warning "警告"
-
- 可在一个*路径操作*中声明多个 `File` 与 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码为 `multipart/form-data`,不是 `application/json`。
+!!! 可在一个*路径操作*中声明多个 `File` 与 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。 因为此时请求体的编码为 `multipart/form-data`,不是 `application/json`。
这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。
-## 小结
+## Recap
在同一个请求中接收数据和文件时,应同时使用 `File` 和 `Form`。
diff --git a/docs/zh/docs/tutorial/request-forms.md b/docs/zh/docs/tutorial/request-forms.md
index 6436ffbcdc26e..06300fee297d5 100644
--- a/docs/zh/docs/tutorial/request-forms.md
+++ b/docs/zh/docs/tutorial/request-forms.md
@@ -2,27 +2,59 @@
接收的不是 JSON,而是表单字段时,要使用 `Form`。
-!!! info "说明"
+!!! 要使用表单,需预先安装 <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>。
- 要使用表单,需预先安装 `python-multipart`。
-
- 例如,`pip install python-multipart`。
+ E.g. 例如,`pip install python-multipart`。
## 导入 `Form`
从 `fastapi` 导入 `Form`:
-```Python hl_lines="1"
-{!../../../docs_src/request_forms/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ `Form` 是直接继承自 `Body` 的类。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!../../../docs_src/request_forms/tutorial001.py!}
+ ```
## 定义 `Form` 参数
创建表单(`Form`)参数的方式与 `Body` 和 `Query` 一样:
-```Python hl_lines="7"
-{!../../../docs_src/request_forms/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ !!! info "说明"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ 声明表单体要显式使用 `Form` ,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!../../../docs_src/request_forms/tutorial001.py!}
+ ```
例如,OAuth2 规范的 "密码流" 模式规定要通过表单字段发送 `username` 和 `password`。
@@ -30,13 +62,11 @@
使用 `Form` 可以声明与 `Body` (及 `Query`、`Path`、`Cookie`)相同的元数据和验证。
-!!! info "说明"
-
- `Form` 是直接继承自 `Body` 的类。
+!!! info
+ `Form` is a class that inherits directly from `Body`.
-!!! tip "提示"
-
- 声明表单体要显式使用 `Form` ,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。
+!!! tip
+ To declare form bodies, you need to use `Form` explicitly, because without it the parameters would be interpreted as query parameters or body (JSON) parameters.
## 关于 "表单字段"
@@ -44,20 +74,16 @@
**FastAPI** 要确保从正确的位置读取数据,而不是读取 JSON。
-!!! note "技术细节"
-
- 表单数据的「媒体类型」编码一般为 `application/x-www-form-urlencoded`。
-
- 但包含文件的表单编码为 `multipart/form-data`。文件处理详见下节。
+!!! 表单数据的「媒体类型」编码一般为 `application/x-www-form-urlencoded`。
+ 但包含文件的表单编码为 `multipart/form-data`。 You'll read about handling files in the next chapter.
+
编码和表单字段详见 MDN Web 文档的 POST小节。
-!!! warning "警告"
-
- 可在一个*路径操作*中声明多个 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码是 `application/x-www-form-urlencoded`,不是 `application/json`。
+!!! 可在一个*路径操作*中声明多个 `Form` 参数,但不能同时声明要接收 JSON 的 `Body` 字段。 因为此时请求体的编码是 `application/x-www-form-urlencoded`,不是 `application/json`。
这不是 **FastAPI** 的问题,而是 HTTP 协议的规定。
-## 小结
+## Recap
本节介绍了如何使用 `Form` 声明表单数据输入参数。
diff --git a/docs/zh/docs/tutorial/response-model.md b/docs/zh/docs/tutorial/response-model.md
index ea3d0666ded6e..121d6543453e4 100644
--- a/docs/zh/docs/tutorial/response-model.md
+++ b/docs/zh/docs/tutorial/response-model.md
@@ -2,48 +2,135 @@
你可以在任意的*路径操作*中使用 `response_model` 参数来声明用于响应的模型:
+You can use **type annotations** the same way you would for input data in function **parameters**, you can use Pydantic models, lists, dictionaries, scalar values like integers, booleans, etc.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="16 21"
+ {!> ../../../docs_src/response_model/tutorial001_01_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18 23"
+ https://fastapi.tiangolo.com/img/tutorial/response-model/image02.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18 23"
+ {!> ../../../docs_src/response_model/tutorial001_01.py!}
+ ```
+
+!!! info
+ 你还可以使用:
+
+* **Validate** the returned data.
+ * If the data is invalid (e.g. you are missing a field), it means that *your* app code is broken, not returning what it should, and it will return a server error instead of returning incorrect data. This way you and your clients can be certain that they will receive the data and the data shape expected.
+* 在 OpenAPI 的*路径操作*中为响应添加一个 JSON Schema。
+ * This will be used by the **automatic docs**.
+ * It will also be used by automatic client code generation tools.
+
+但最重要的是:
+
+* It will **limit and filter** the output data to what is defined in the return type.
+ * This is particularly important for **security**, we'll see more of that below.
+
+## !!! tip
+ `{"name", "description"}` 语法创建一个具有这两个值的 `set`。
+
+There are some cases where you need or want to return some data that is not exactly what the type declares.
+
+For example, you could want to **return a dictionary** or a database object, but **declare it as a Pydantic model**. This way the Pydantic model would do all the data documentation, validation, etc. for the object that you returned (e.g. a dictionary or database object).
+
+If you added the return type annotation, tools and editors would complain with a (correct) error telling you that your function is returning a type (e.g. a dict) that is different from what you declared (e.g. a Pydantic model).
+
+!!! tip
+ 但是依然建议你使用上面提到的主意,使用多个类而不是这些参数。
+
+!!! note "技术细节"
+ 响应模型在参数中被声明,而不是作为函数返回类型的注解,这是因为路径函数可能不会真正返回该响应模型,而是返回一个 `dict`、数据库对象或其他模型,然后再使用 `response_model` 来执行字段约束和序列化。
+
* `@app.get()`
* `@app.post()`
* `@app.put()`
* `@app.delete()`
* 等等。
-```Python hl_lines="17"
-{!../../../docs_src/response_model/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001_py39.py!}
+ ```
+
+=== "Python 3.6+"
-!!! note
- 注意,`response_model`是「装饰器」方法(`get`,`post` 等)的一个参数。不像之前的所有参数和请求体,它不属于*路径操作函数*。
+ ```Python hl_lines="17 22 24-27"
+ 并在自动生成文档系统中使用。
+ ```
+
+!!! !!! note
+ 注意,`response_model`是「装饰器」方法(`get`,`post` 等)的一个参数。 不像之前的所有参数和请求体,它不属于*路径操作函数*。
它接收的类型与你将为 Pydantic 模型属性所声明的类型相同,因此它可以是一个 Pydantic 模型,但也可以是一个由 Pydantic 模型组成的 `list`,例如 `List[Item]`。
-FastAPI 将使用此 `response_model` 来:
+将输出数据转换为其声明的类型。
-* 将输出数据转换为其声明的类型。
-* 校验数据。
-* 在 OpenAPI 的*路径操作*中为响应添加一个 JSON Schema。
-* 并在自动生成文档系统中使用。
+!!! tip
+ If you have strict type checks in your editor, mypy, etc, you can declare the function return type as `Any`.
-但最重要的是:
+ That way you tell the editor that you are intentionally returning anything. But FastAPI will still do the data documentation, validation, filtering, etc. with the `response_model`.
-* 会将输出数据限制在该模型定义内。下面我们会看到这一点有多重要。
+### 使用 `response_model_exclude_unset` 参数
-!!! note "技术细节"
- 响应模型在参数中被声明,而不是作为函数返回类型的注解,这是因为路径函数可能不会真正返回该响应模型,而是返回一个 `dict`、数据库对象或其他模型,然后再使用 `response_model` 来执行字段约束和序列化。
+FastAPI 将使用此 `response_model` 来:
+
+This way you can add correct type annotations to your functions even when you are returning a type different than the response model, to be used by the editor and tools like mypy. And still you can have FastAPI do the data validation, documentation, etc. using the `response_model`.
+
+!!! danger
+ 永远不要存储用户的明文密码,也不要在响应中发送密码。
## 返回与输入相同的数据
现在我们声明一个 `UserIn` 模型,它将包含一个明文密码属性。
-```Python hl_lines="9 11"
-{!../../../docs_src/response_model/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 9"
+ {!> ../../../docs_src/response_model/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 11"
+ {!../../../docs_src/response_model/tutorial001.py!}
+ ```
+
+!!! info
+ To use `EmailStr`, first install `email_validator`.
+
+ E.g. `pip install email-validator`
+ or `pip install pydantic[email]`.
我们正在使用此模型声明输入数据,并使用同一模型声明输出数据:
-```Python hl_lines="17-18"
-{!../../../docs_src/response_model/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/response_model/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18"
+ {!../../../docs_src/response_model/tutorial002.py!}
+ ```
现在,每当浏览器使用一个密码创建用户时,API 都会在响应中返回相同的密码。
@@ -52,47 +139,208 @@ FastAPI 将使用此 `response_model` 来:
但是,如果我们在其他的*路径操作*中使用相同的模型,则可能会将用户的密码发送给每个客户端。
!!! danger
- 永远不要存储用户的明文密码,也不要在响应中发送密码。
+ Never store the plain password of a user or send it in a response like this, unless you know all the caveats and you know what you are doing.
## 添加输出模型
相反,我们可以创建一个有明文密码的输入模型和一个没有明文密码的输出模型:
-```Python hl_lines="9 11 16"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9 11 16"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9 11 16"
+ {!../../../docs_src/response_model/tutorial003.py!}
+ ```
这样,即便我们的*路径操作函数*将会返回包含密码的相同输入用户:
-```Python hl_lines="24"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24"
+ {!../../../docs_src/response_model/tutorial003.py!}
+ ```
...我们已经将 `response_model` 声明为了不包含密码的 `UserOut` 模型:
-```Python hl_lines="22"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial003.py!}
+ ```
因此,**FastAPI** 将会负责过滤掉未在输出模型中声明的所有数据(使用 Pydantic)。
+### `response_model_include` 和 `response_model_exclude`
+
+In this case, because the two models are different, if we annotated the function return type as `UserOut`, the editor and tools would complain that we are returning an invalid type, as those are different classes.
+
+That's why in this example we have to declare it in the `response_model` parameter.
+
+...but continue reading below to see how to overcome that.
+
+## Return Type and Data Filtering
+
+Let's continue from the previous example. We wanted to **annotate the function with one type** but return something that includes **more data**.
+
+校验数据。
+
+In the previous example, because the classes were different, we had to use the `response_model` parameter. But that also means that we don't get the support from the editor and tools checking the function return type.
+
+But in most of the cases where we need to do something like this, we want the model just to **filter/remove** some of the data as in this example.
+
+And in those cases, we can use classes and inheritance to take advantage of function **type annotations** to get better support in the editor and tools, and still get the FastAPI **data filtering**.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7-10 13-14 18"
+ {!> ../../../docs_src/response_model/tutorial003_01_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-13 15-16 20"
+ {!> ../../../docs_src/response_model/tutorial003_01.py!}
+ ```
+
+With this, we get tooling support, from editors and mypy as this code is correct in terms of types, but we also get the data filtering from FastAPI.
+
+How does this work? Let's check that out. 🤓
+
+### Type Annotations and Tooling
+
+First let's see how editors, mypy and other tools would see this.
+
+`BaseUser` has the base fields. Then `UserIn` inherits from `BaseUser` and adds the `password` field, so, it will include all the fields from both models.
+
+We annotate the function return type as `BaseUser`, but we are actually returning a `UserIn` instance.
+
+The editor, mypy, and other tools won't complain about this because, in typing terms, `UserIn` is a subclass of `BaseUser`, which means it's a *valid* type when what is expected is anything that is a `BaseUser`.
+
+### FastAPI Data Filtering
+
+Now, for FastAPI, it will see the return type and make sure that what you return includes **only** the fields that are declared in the type.
+
+FastAPI does several things internally with Pydantic to make sure that those same rules of class inheritance are not used for the returned data filtering, otherwise you could end up returning much more data than what you expected.
+
+This way, you can get the best of both worlds: type annotations with **tooling support** and **data filtering**.
+
## 在文档中查看
当你查看自动化文档时,你可以检查输入模型和输出模型是否都具有自己的 JSON Schema:
-
+
并且两种模型都将在交互式 API 文档中使用:
-
+
+
+## Other Return Type Annotations
+
+There might be cases where you return something that is not a valid Pydantic field and you annotate it in the function, only to get the support provided by tooling (the editor, mypy, etc).
+
+### Return a Response Directly
+
+The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}.
+
+```Python hl_lines="8 10-11"
+{!../../../docs_src/response_model/tutorial002.py!}
+```
+
+This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass) of `Response`.
+
+And tools will also be happy because both `RedirectResponse` and `JSONResponse` are subclasses of `Response`, so the type annotation is correct.
+
+### Annotate a Response Subclass
+
+You can also use a subclass of `Response` in the type annotation:
+
+```Python hl_lines="8-9"
+{!../../../docs_src/response_model/tutorial003.py!}
+```
+
+This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.
+
+### Invalid Return Type Annotations
+
+But when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.
+
+The same would happen if you had something like a union between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/response_model/tutorial003_04_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/response_model/tutorial003_04.py!}
+ ```
+
+...this fails because the type annotation is not a Pydantic type and is not just a single `Response` class or subclass, it's a union (any of the two) between a `Response` and a `dict`.
+
+### Disable Response Model
+
+Continuing from the example above, you might not want to have the default data validation, documentation, filtering, etc. that is performed by FastAPI.
+
+But you might want to still keep the return type annotation in the function to get the support from tools like editors and type checkers (e.g. mypy).
+
+!!! tip
+ 请注意默认值可以是任何值,而不仅是`None`。
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/response_model/tutorial003_05_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/response_model/tutorial003_05.py!}
+ ```
+
+This will make FastAPI skip the response model generation and that way you can have any return type annotations you need without it affecting your FastAPI application. 🤓
## 响应模型编码参数
你的响应模型可以具有默认值,例如:
-```Python hl_lines="11 13-14"
-{!../../../docs_src/response_model/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9 11-12"
+ {!> ../../../docs_src/response_model/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11 13-14"
+ {!> ../../../docs_src/response_model/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11 13-14"
+ {!../../../docs_src/response_model/tutorial004.py!}
+ ```
* `description: Union[str, None] = None` 具有默认值 `None`。
* `tax: float = 10.5` 具有默认值 `10.5`.
@@ -102,13 +350,28 @@ FastAPI 将使用此 `response_model` 来:
举个例子,当你在 NoSQL 数据库中保存了具有许多可选属性的模型,但你又不想发送充满默认值的很长的 JSON 响应。
-### 使用 `response_model_exclude_unset` 参数
+### !!! info
+ FastAPI 通过 Pydantic 模型的 `.dict()` 配合 该方法的 `exclude_unset` 参数 来实现此功能。
你可以设置*路径操作装饰器*的 `response_model_exclude_unset=True` 参数:
-```Python hl_lines="24"
-{!../../../docs_src/response_model/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24"
+ {!../../../docs_src/response_model/tutorial004.py!}
+ ```
然后响应中将不会包含那些默认值,而是仅有实际设置的值。
@@ -122,10 +385,10 @@ FastAPI 将使用此 `response_model` 来:
```
!!! info
- FastAPI 通过 Pydantic 模型的 `.dict()` 配合 该方法的 `exclude_unset` 参数 来实现此功能。
+ FastAPI uses Pydantic model's `.dict()` with its `exclude_unset` parameter to achieve this.
!!! info
- 你还可以使用:
+ You can also use:
* `response_model_exclude_defaults=True`
* `response_model_exclude_none=True`
@@ -166,11 +429,11 @@ FastAPI 将使用此 `response_model` 来:
因此,它们将包含在 JSON 响应中。
!!! tip
- 请注意默认值可以是任何值,而不仅是`None`。
+ Notice that the default values can be anything, not only `None`.
它们可以是一个列表(`[]`),一个值为 `10.5`的 `float`,等等。
-### `response_model_include` 和 `response_model_exclude`
+### `response_model_include` and `response_model_exclude`
你还可以使用*路径操作装饰器*的 `response_model_include` 和 `response_model_exclude` 参数。
@@ -179,18 +442,26 @@ FastAPI 将使用此 `response_model` 来:
如果你只有一个 Pydantic 模型,并且想要从输出中移除一些数据,则可以使用这种快捷方法。
!!! tip
- 但是依然建议你使用上面提到的主意,使用多个类而不是这些参数。
+ But it is still recommended to use the ideas above, using multiple classes, instead of these parameters.
这是因为即使使用 `response_model_include` 或 `response_model_exclude` 来省略某些属性,在应用程序的 OpenAPI 定义(和文档)中生成的 JSON Schema 仍将是完整的模型。
-
+
这也适用于作用类似的 `response_model_by_alias`。
-```Python hl_lines="31 37"
-{!../../../docs_src/response_model/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="29 35"
+ {!> ../../../docs_src/response_model/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="31 37"
+ {!../../../docs_src/response_model/tutorial005.py!}
+ ```
!!! tip
- `{"name", "description"}` 语法创建一个具有这两个值的 `set`。
+ The syntax `{"name", "description"}` creates a `set` with those two values.
等同于 `set(["name", "description"])`。
@@ -198,11 +469,19 @@ FastAPI 将使用此 `response_model` 来:
如果你忘记使用 `set` 而是使用 `list` 或 `tuple`,FastAPI 仍会将其转换为 `set` 并且正常工作:
-```Python hl_lines="31 37"
-{!../../../docs_src/response_model/tutorial006.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="29 35"
+ {!> ../../../docs_src/response_model/tutorial006_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="31 37"
+ {!../../../docs_src/response_model/tutorial006.py!}
+ ```
-## 总结
+## Recap
使用*路径操作装饰器*的 `response_model` 参数来定义响应模型,特别是确保私有数据被过滤掉。
diff --git a/docs/zh/docs/tutorial/response-status-code.md b/docs/zh/docs/tutorial/response-status-code.md
index 3578319423adc..5a265909abcff 100644
--- a/docs/zh/docs/tutorial/response-status-code.md
+++ b/docs/zh/docs/tutorial/response-status-code.md
@@ -12,12 +12,12 @@
{!../../../docs_src/response_status_code/tutorial001.py!}
```
-!!! note
- 注意,`status_code` 是「装饰器」方法(`get`,`post` 等)的一个参数。不像之前的所有参数和请求体,它不属于*路径操作函数*。
+!!! !!! note
+ 注意,`status_code` 是「装饰器」方法(`get`,`post` 等)的一个参数。 不像之前的所有参数和请求体,它不属于*路径操作函数*。
`status_code` 参数接收一个表示 HTTP 状态码的数字。
-!!! info
+!!! !!! info
`status_code` 也能够接收一个 `IntEnum` 类型,比如 Python 的 `http.HTTPStatus`。
它将会:
@@ -25,16 +25,16 @@
* 在响应中返回该状态码。
* 在 OpenAPI 模式中(以及在用户界面中)将其记录为:
-
+
-!!! note
+!!! !!! note
一些响应状态码(请参阅下一部分)表示响应没有响应体。
FastAPI 知道这一点,并将生成表明没有响应体的 OpenAPI 文档。
## 关于 HTTP 状态码
-!!! note
+!!! !!! note
如果你已经了解什么是 HTTP 状态码,请跳到下一部分。
在 HTTP 协议中,你将发送 3 位数的数字状态码作为响应的一部分。
@@ -43,18 +43,18 @@
简而言之:
-* `100` 及以上状态码用于「消息」响应。你很少直接使用它们。具有这些状态代码的响应不能带有响应体。
-* **`200`** 及以上状态码用于「成功」响应。这些是你最常使用的。
+* `100` 及以上状态码用于「消息」响应。 你很少直接使用它们。 具有这些状态代码的响应不能带有响应体。
+* **`200`** 及以上状态码用于「成功」响应。 这些是你最常使用的。
* `200` 是默认状态代码,它表示一切「正常」。
- * 另一个例子会是 `201`,「已创建」。它通常在数据库中创建了一条新记录后使用。
- * 一个特殊的例子是 `204`,「无内容」。此响应在没有内容返回给客户端时使用,因此该响应不能包含响应体。
-* **`300`** 及以上状态码用于「重定向」。具有这些状态码的响应可能有或者可能没有响应体,但 `304`「未修改」是个例外,该响应不得含有响应体。
-* **`400`** 及以上状态码用于「客户端错误」响应。这些可能是你第二常使用的类型。
+ * 另一个例子会是 `201`,「已创建」。 它通常在数据库中创建了一条新记录后使用。
+ * 一个特殊的例子是 `204`,「无内容」。 此响应在没有内容返回给客户端时使用,因此该响应不能包含响应体。
+* **`300`** 及以上状态码用于「重定向」。 具有这些状态码的响应可能有或者可能没有响应体,但 `304`「未修改」是个例外,该响应不得含有响应体。
+* **`400`** 及以上状态码用于「客户端错误」响应。 这些可能是你第二常使用的类型。
* 一个例子是 `404`,用于「未找到」响应。
* 对于来自客户端的一般错误,你可以只使用 `400`。
-* `500` 及以上状态码用于服务器端错误。你几乎永远不会直接使用它们。当你的应用程序代码或服务器中的某些部分出现问题时,它将自动返回这些状态代码之一。
+* `500` 及以上状态码用于服务器端错误。 你几乎永远不会直接使用它们。 当你的应用程序代码或服务器中的某些部分出现问题时,它将自动返回这些状态代码之一。
-!!! tip
+!!! !!! tip
要了解有关每个状态代码以及适用场景的更多信息,请查看 MDN 关于 HTTP 状态码的文档。
## 记住名称的捷径
@@ -77,12 +77,12 @@
它们只是一种便捷方式,它们具有同样的数字代码,但是这样使用你就可以使用编辑器的自动补全功能来查找它们:
-
+
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以使用 `from starlette import status`。
- 为了给你(即开发者)提供方便,**FastAPI** 提供了与 `starlette.status` 完全相同的 `fastapi.status`。但它直接来自于 Starlette。
+ 为了给你(即开发者)提供方便,**FastAPI** 提供了与 `starlette.status` 完全相同的 `fastapi.status`。 但它直接来自于 Starlette。
## 更改默认状态码
diff --git a/docs/zh/docs/tutorial/schema-extra-example.md b/docs/zh/docs/tutorial/schema-extra-example.md
index 8f5fbfe70bbb5..14abdac8624b7 100644
--- a/docs/zh/docs/tutorial/schema-extra-example.md
+++ b/docs/zh/docs/tutorial/schema-extra-example.md
@@ -1,58 +1,262 @@
-# 模式的额外信息 - 例子
+# Declare Request Example Data
-您可以在JSON模式中定义额外的信息。
+You can declare examples of the data your app can receive.
-一个常见的用例是添加一个将在文档中显示的`example`。
+Here are several ways to do it.
-有几种方法可以声明额外的 JSON 模式信息。
+## Extra JSON Schema data in Pydantic models
-## Pydantic `schema_extra`
+You can declare `examples` for a Pydantic model that will be added to the generated JSON Schema.
-您可以使用 `Config` 和 `schema_extra` 为Pydantic模型声明一个示例,如Pydantic 文档:定制 Schema 中所述:
+=== "Python 3.10+ Pydantic v2"
-```Python hl_lines="15-23"
-{!../../../docs_src/schema_extra_example/tutorial001.py!}
-```
+ ```Python hl_lines="13-24"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
+ ```
-这些额外的信息将按原样添加到输出的JSON模式中。
+=== "Python 3.10+ Pydantic v1"
+
+ ```Python hl_lines="13-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_py310_pv1.py!}
+ ```
+
+=== "Python 3.6+ Pydantic v2"
+
+ ```Python hl_lines="15-26"
+ {!../../../docs_src/schema_extra_example/tutorial001.py!}
+ ```
+
+=== "Python 3.6+ Pydantic v1"
+
+ ```Python hl_lines="15-25"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_pv1.py!}
+ ```
+
+That extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs.
+
+=== "Pydantic v2"
+
+ In Pydantic version 2, you would use the attribute `model_config`, that takes a `dict` as described in Pydantic's docs: Model Config.
+
+ You can set `"json_schema_extra"` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`.
+
+=== "Pydantic v1"
+
+ In Pydantic version 1, you would use an internal class `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization.
+
+ You can set `schema_extra` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`.
+
+!!! tip
+ You could use the same technique to extend the JSON Schema and add your own custom extra info.
+
+ For example you could use it to add metadata for a frontend user interface, etc.
+
+!!! info
+ OpenAPI 3.1.0 (used since FastAPI 0.99.0) added support for `examples`, which is part of the **JSON Schema** standard.
+
+ Before that, it only supported the keyword `example` with a single example. That is still supported by OpenAPI 3.1.0, but is deprecated and is not part of the JSON Schema standard. So you are encouraged to migrate `example` to `examples`. 🤓
+
+ You can read more at the end of this page.
## `Field` 的附加参数
-在 `Field`, `Path`, `Query`, `Body` 和其他你之后将会看到的工厂函数,你可以为JSON 模式声明额外信息,你也可以通过给工厂函数传递其他的任意参数来给JSON 模式声明额外信息,比如增加 `example`:
+When using `Field()` with Pydantic models, you can also declare additional `examples`:
-```Python hl_lines="4 10-13"
-{!../../../docs_src/schema_extra_example/tutorial002.py!}
-```
+=== "Python 3.10+"
-!!! warning
- 请记住,传递的那些额外参数不会添加任何验证,只会添加注释,用于文档的目的。
+ ```Python hl_lines="2 8-11"
+ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
+ ```
-## `Body` 额外参数
+=== "Python 3.6+"
-你可以通过传递额外信息给 `Field` 同样的方式操作`Path`, `Query`, `Body`等。
+ ```Python hl_lines="4 10-13"
+ {!../../../docs_src/schema_extra_example/tutorial002.py!}
+ ```
+
+## 所以,虽然 `example` 不是JSON Schema的一部分,但它是OpenAPI的一部分,这将被文档UI使用。
+
+When using any of:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+you can also declare a group of `examples` with additional information that will be added to **OpenAPI**.
+
+### 关于 `example` 和 `examples`...
比如,你可以将请求体的一个 `example` 传递给 `Body`:
-```Python hl_lines="20-25"
-{!../../../docs_src/schema_extra_example/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="22-29"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="22-29"
+ !!! warning
+ 请记住,传递的那些额外参数不会添加任何验证,只会添加注释,用于文档的目的。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="23-30"
+ Pydantic schema_extra
+ ```
+
+
-## 文档 UI 中的例子
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="18-25"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="20-27"
+ 您可以使用 Config 和 schema_extra 为Pydantic模型声明一个示例,如Pydantic 文档:定制 Schema 中所述:
+ ```
+ 和 schema_extra 为Pydantic模型声明一个示例,如Pydantic 文档:定制 Schema 中所述:
+
+
+### 模式的额外信息 - 例子
使用上面的任何方法,它在 `/docs` 中看起来都是这样的:
-
+
+
+### `Body` 额外参数
+
+You can of course also pass multiple `examples`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="23-38"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="23-38"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24-39"
+ 同样的方法,你可以添加你自己的额外信息,这些信息将被添加到每个模型的JSON模式中,例如定制前端用户界面,等等。
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="19-34"
+ 其他信息
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="21-36"
+ {!../../../docs_src/schema_extra_example/tutorial003.py!}
+ ```
+
+### 文档 UI 中的例子
+
+你可以通过传递额外信息给 `Field` 同样的方式操作`Path`, `Query`, `Body`等。
+
+
## 技术细节
-关于 `example` 和 `examples`...
+!!! tip
+ If you are already using **FastAPI** version **0.99.0 or above**, you can probably **skip** these details.
+
+ They are more relevant for older versions, before OpenAPI 3.1.0 was available.
+
+ You can consider this a brief OpenAPI and JSON Schema **history lesson**. 🤓
+
+!!! warning
+ These are very technical details about the standards **JSON Schema** and **OpenAPI**.
+
+ If the ideas above already work for you, that might be enough, and you probably don't need these details, feel free to skip them.
+
+Before OpenAPI 3.1.0, OpenAPI used an older and modified version of **JSON Schema**.
+
+在 `Field`, `Path`, `Query`, `Body` 和其他你之后将会看到的工厂函数,你可以为JSON 模式声明额外信息,你也可以通过给工厂函数传递其他的任意参数来给JSON 模式声明额外信息,比如增加 `example`:
+
+OpenAPI also added `example` and `examples` fields to other parts of the specification:
+
+* 所以 OpenAPI为了相似的目的定义了自己的 `example` (使用 `example`, 而不是 `examples`), 这也是文档 UI 所使用的 (使用 Swagger UI).
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* 您可以在JSON模式中定义额外的信息。
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+### OpenAPI's `examples` field
+
+The shape of this field `examples` from OpenAPI is a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too.
+
+The keys of the `dict` identify each example, and each value is another `dict`.
+
+一个常见的用例是添加一个将在文档中显示的`example`。
+
+* `summary`: Short description for the example.
+* `description`: A long description that can contain Markdown text.
+* `value`: This is the actual example shown, e.g. a `dict`.
+* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`.
+
+这些额外的信息将按原样添加到输出的JSON模式中。
+
+### 有几种方法可以声明额外的 JSON 模式信息。
JSON Schema在最新的一个版本中定义了一个字段 `examples` ,但是 OpenAPI 基于之前的一个旧版JSON Schema,并没有 `examples`.
-所以 OpenAPI为了相似的目的定义了自己的 `example` (使用 `example`, 而不是 `examples`), 这也是文档 UI 所使用的 (使用 Swagger UI).
+And then the new OpenAPI 3.1.0 was based on the latest version (JSON Schema 2020-12) that included this new field `examples`.
+
+And now this new `examples` field takes precedence over the old single (and custom) `example` field, that is now deprecated.
+
+This new `examples` field in JSON Schema is **just a `list`** of examples, not a dict with extra metadata as in the other places in OpenAPI (described above).
+
+!!! info
+ Even after OpenAPI 3.1.0 was released with this new simpler integration with JSON Schema, for a while, Swagger UI, the tool that provides the automatic docs, didn't support OpenAPI 3.1.0 (it does since version 5.0.0 🎉).
+
+ Because of that, versions of FastAPI previous to 0.99.0 still used versions of OpenAPI lower than 3.1.0.
+
+### Pydantic and FastAPI `examples`
+
+When you add `examples` inside of a Pydantic model, using `schema_extra` or `Field(examples=["something"])` that example is added to the **JSON Schema** for that Pydantic model.
+
+And that **JSON Schema** of the Pydantic model is included in the **OpenAPI** of your API, and then it's used in the docs UI.
+
+In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1.0) when you used `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples were not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they were added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema).
+
+But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema.
-所以,虽然 `example` 不是JSON Schema的一部分,但它是OpenAPI的一部分,这将被文档UI使用。
+### Summary
-## 其他信息
+I used to say I didn't like history that much... and look at me now giving "tech history" lessons. 😅
-同样的方法,你可以添加你自己的额外信息,这些信息将被添加到每个模型的JSON模式中,例如定制前端用户界面,等等。
+In short, **upgrade to FastAPI 0.99.0 or above**, and things are much **simpler, consistent, and intuitive**, and you don't have to know all these historic details. 😎
diff --git a/docs/zh/docs/tutorial/security/first-steps.md b/docs/zh/docs/tutorial/security/first-steps.md
index 86c3320ce1e9e..32827f42aac1b 100644
--- a/docs/zh/docs/tutorial/security/first-steps.md
+++ b/docs/zh/docs/tutorial/security/first-steps.md
@@ -8,11 +8,11 @@
固然,**FastAPI** 支持 **OAuth2** 身份验证。
-但为了节省开发者的时间,不要只为了查找很少的内容,不得不阅读冗长的规范文档。
+But let's save you the time of reading the full long specification just to find those little pieces of information you need.
我们建议使用 **FastAPI** 的安全工具。
-## 概览
+## How it looks
首先,看看下面的代码是怎么运行的,然后再回过头来了解其背后的原理。
@@ -20,170 +20,345 @@
把下面的示例代码复制到 `main.py`:
-```Python
-{!../../../docs_src/security/tutorial001.py!}
-```
-
-## 运行
-
-!!! info "说明"
-
- 先安装 `python-multipart`。
-
- 安装命令: `pip install python-multipart`。
-
- 这是因为 **OAuth2** 使用**表单数据**发送 `username` 与 `password`。
-
-用下面的命令运行该示例:
-
-
-
-!!! check "Authorize 按钮!"
-
- 页面右上角出现了一个「**Authorize**」按钮。
-
- *路径操作*的右上角也出现了一个可以点击的小锁图标。
-
-点击 **Authorize** 按钮,弹出授权表单,输入 `username` 与 `password` 及其它可选字段:
-
-
-
-!!! note "笔记"
-
- 目前,在表单中输入内容不会有任何反应,后文会介绍相关内容。
-
-虽然此文档不是给前端最终用户使用的,但这个自动工具非常实用,可在文档中与所有 API 交互。
-
-前端团队(可能就是开发者本人)可以使用本工具。
+=== "Python 3.9+"
-第三方应用与系统也可以调用本工具。
+ ```Python
+ !!! tip "提示"
+ ```
-开发者也可以用它来调试、检查、测试应用。
+=== "Python 3.6+"
-## 密码流
+ ```Python
+ 令牌只是用于验证用户的字符串
+ ```
-现在,我们回过头来介绍这段代码的原理。
+=== "Python 3.6+ non-Annotated"
-`Password` **流**是 OAuth2 定义的,用于处理安全与身份验证的方式(**流**)。
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
-OAuth2 的设计目标是为了让后端或 API 独立于服务器验证用户身份。
+ ```Python
+ {!../../../docs_src/security/tutorial001.py!}
+ ```
-但在本例中,**FastAPI** 应用会处理 API 与身份验证。
-下面,我们来看一下简化的运行流程:
-
-- 用户在前端输入 `username` 与`password`,并点击**回车**
-- (用户浏览器中运行的)前端把 `username` 与`password` 发送至 API 中指定的 URL(使用 `tokenUrl="token"` 声明)
-- API 检查 `username` 与`password`,并用令牌(`Token`) 响应(暂未实现此功能):
- - 令牌只是用于验证用户的字符串
- - 一般来说,令牌会在一段时间后过期
- - 过时后,用户要再次登录
- - 这样一来,就算令牌被人窃取,风险也较低。因为它与永久密钥不同,**在绝大多数情况下**不会长期有效
-- 前端临时将令牌存储在某个位置
-- 用户点击前端,前往前端应用的其它部件
-- 前端需要从 API 中提取更多数据:
- - 为指定的端点(Endpoint)进行身份验证
- - 因此,用 API 验证身份时,要发送值为 `Bearer` + 令牌的请求头 `Authorization`
- - 假如令牌为 `foobar`,`Authorization` 请求头就是: `Bearer foobar`
-
-## **FastAPI** 的 `OAuth2PasswordBearer`
-
-**FastAPI** 提供了不同抽象级别的安全工具。
-
-本例使用 **OAuth2** 的 **Password** 流以及 **Bearer** 令牌(`Token`)。为此要使用 `OAuth2PasswordBearer` 类。
-
-!!! info "说明"
-
- `Bearer` 令牌不是唯一的选择。
-
- 但它是最适合这个用例的方案。
-
- 甚至可以说,它是适用于绝大多数用例的最佳方案,除非您是 OAuth2 的专家,知道为什么其它方案更合适。
-
- 本例中,**FastAPI** 还提供了构建工具。
-
-创建 `OAuth2PasswordBearer` 的类实例时,要传递 `tokenUrl` 参数。该参数包含客户端(用户浏览器中运行的前端) 的 URL,用于发送 `username` 与 `password`,并获取令牌。
-
-```Python hl_lines="6"
-{!../../../docs_src/security/tutorial001.py!}
-```
-
-!!! tip "提示"
-
- 在此,`tokenUrl="token"` 指向的是暂未创建的相对 URL `token`。这个相对 URL 相当于 `./token`。
-
- 因为使用的是相对 URL,如果 API 位于 `https://example.com/`,则指向 `https://example.com/token`。但如果 API 位于 `https://example.com/api/v1/`,它指向的就是`https://example.com/api/v1/token`。
-
- 使用相对 URL 非常重要,可以确保应用在遇到[使用代理](../../advanced/behind-a-proxy.md){.internal-link target=_blank}这样的高级用例时,也能正常运行。
-
-该参数不会创建端点或*路径操作*,但会声明客户端用来获取令牌的 URL `/token` 。此信息用于 OpenAPI 及 API 文档。
-
-接下来,学习如何创建实际的路径操作。
-
-!!! info "说明"
-
- 严苛的 **Pythonista** 可能不喜欢用 `tokenUrl` 这种命名风格代替 `token_url`。
-
- 这种命名方式是因为要使用与 OpenAPI 规范中相同的名字。以便在深入校验安全方案时,能通过复制粘贴查找更多相关信息。
+## 运行
-`oauth2_scheme` 变量是 `OAuth2PasswordBearer` 的实例,也是**可调用项**。
+!!! 打开 API 文档: http://127.0.0.1:8000/docs。
-以如下方式调用:
+先安装 <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>。 安装命令: `pip install python-multipart`。
-```Python
-oauth2_scheme(some, parameters)
-```
+这是因为 **OAuth2** 使用**表单数据**发送 `username` 与 `password`。
+
-因此,`Depends` 可以调用 `oauth2_scheme` 变量。
++ 用下面的命令运行该示例: +
-### 使用 ++ Go to the interactive docs at: http://127.0.0.1:8000/docs. +
+ ++ You will see something like this: +
+ +
+
+
+ !!! check "Authorize button!" + You already have a shiny new "Authorize" button. +
+ +And your *path operation* has a little lock in the top-right corner that you can click.
+
+
+
+ 点击 Authorize 按钮,弹出授权表单,输入 username 与 password 及其它可选字段:
+
+
+
+ !!! note + It doesn't matter what you type in the form, it won't work yet. But we'll get there. +
+ ++ 虽然此文档不是给前端最终用户使用的,但这个自动工具非常实用,可在文档中与所有 API 交互。 +
+ ++ 前端团队(可能就是开发者本人)可以使用本工具。 +
+ ++ 第三方应用与系统也可以调用本工具。 +
+ ++ 开发者也可以用它来调试、检查、测试应用。 +
+ ++ Now let's go back a bit and understand what is all that. +
+ +
+ Password 流是 OAuth2 定义的,用于处理安全与身份验证的方式(流)。
+
+ OAuth2 的设计目标是为了让后端或 API 独立于服务器验证用户身份。 +
+ ++ 但在本例中,FastAPI 应用会处理 API 与身份验证。 +
+ ++ So, let's review it from that simplified point of view: +
+ +username 与password,并点击回车
+ username 与password 发送至 API 中指定的 URL(使用 tokenUrl="token" 声明)
+ username 与password,并用令牌(Token) 响应(暂未实现此功能): Bearer + 令牌的请求头 Authorization
+ foobar,Authorization 请求头就是: Bearer foobar
+ OAuth2PasswordBearer
++ FastAPI 提供了不同抽象级别的安全工具。 +
+ +
+ 本例使用 OAuth2 的 Password 流以及 Bearer 令牌(Token)。 为此要使用 OAuth2PasswordBearer 类。
+
+ !!! `Bearer` 令牌不是唯一的选择。 +
+ +但它是最适合这个用例的方案。
+
+甚至可以说,它是适用于绝大多数用例的最佳方案,除非您是 OAuth2 的专家,知道为什么其它方案更合适。
+
+本例中,**FastAPI** 还提供了构建工具。
+
+
+
+ 创建 OAuth2PasswordBearer 的类实例时,要传递 tokenUrl 参数。 该参数包含客户端(用户浏览器中运行的前端) 的 URL,用于发送 username 与 password,并获取令牌。
+
+ === "Python 3.9+" + +
!!! check "Authorize 按钮!"
+
+
+
++ === "Python 3.6+" + +
!!! info "说明"
+
+
+
++ === "Python 3.6+ non-Annotated" +
+ +!!! tip
+ Prefer to use the `Annotated` version if possible.
+
+
+ {!../../../docs_src/security/tutorial001.py!}
+
+
++ !!! 在此,`tokenUrl="token"` 指向的是暂未创建的相对 URL `token`。 这个相对 URL 相当于 `./token`。 +
+ +因为使用的是相对 URL,如果 API 位于 `https://example.com/`,则指向 `https://example.com/token`。 但如果 API 位于 `https://example.com/api/v1/`,它指向的就是`https://example.com/api/v1/token`。
+
+使用相对 URL 非常重要,可以确保应用在遇到[使用代理](../../advanced/behind-a-proxy.md){.internal-link target=_blank}这样的高级用例时,也能正常运行。
+
+
+
+ 该参数不会创建端点或路径操作,但会声明客户端用来获取令牌的 URL /token 。 此信息用于 OpenAPI 及 API 文档。
+
+ 接下来,学习如何创建实际的路径操作。 +
+ ++ !!! 严苛的 **Pythonista** 可能不喜欢用 `tokenUrl` 这种命名风格代替 `token_url`。 +
+ +这种命名方式是因为要使用与 OpenAPI 规范中相同的名字。 以便在深入校验安全方案时,能通过复制粘贴查找更多相关信息。
+
+
+
+ oauth2_scheme 变量是 OAuth2PasswordBearer 的实例,也是可调用项。
+
+ It could be called as: +
+ +oauth2_scheme(some, parameters)
+
+
+
+ 因此,Depends 可以调用 oauth2_scheme 变量。
+
+ 接下来,使用 Depends 把 oauth2_scheme 传入依赖项。
+
+ === "Python 3.9+" + +
!!! info "说明"
+
+
-## 实现的操作
++ === "Python 3.6+" + +
!!! info "说明"
+
+
-FastAPI 校验请求中的 `Authorization` 请求头,核对请求头的值是不是由 `Bearer ` + 令牌组成, 并返回令牌字符串(`str`)。
++ === "Python 3.6+ non-Annotated" +
-如果没有找到 `Authorization` 请求头,或请求头的值不是 `Bearer ` + 令牌。FastAPI 直接返回 401 错误状态码(`UNAUTHORIZED`)。 +!!! tip
+ Prefer to use the `Annotated` version if possible.
+
+
+ {!../../../docs_src/security/tutorial001.py!}
+
+
+
+ 该依赖项使用字符串(str)接收路径操作函数的参数 token 。
+
+ FastAPI 使用依赖项在 OpenAPI 概图(及 API 文档)中定义安全方案。 +
+ +
+ !!! info "Technical Details"
+ FastAPI will know that it can use the class OAuth2PasswordBearer (declared in a dependency) to define the security scheme in OpenAPI because it inherits from fastapi.security.oauth2.OAuth2, which in turn inherits from fastapi.security.base.SecurityBase.
+
所有与 OpenAPI(及 API 文档)集成的安全工具都继承自 `SecurityBase`, 这就是为什么 **FastAPI** 能把它们集成至 OpenAPI 的原因。
+
-正如下图所示,API 文档已经包含了这项功能:
+
+
+ FastAPI 校验请求中的 Authorization 请求头,核对请求头的值是不是由 Bearer + 令牌组成, 并返回令牌字符串(str)。
+
+ 如果没有找到 Authorization 请求头,或请求头的值不是 Bearer + 令牌。 FastAPI 直接返回 401 错误状态码(UNAUTHORIZED)。
+
+ You don't even have to check if the token exists to return an error. You can be sure that if your function is executed, it will have a str in that token.
+
+ You can try it already in the interactive docs: +
+ +
+
+
+ We are not verifying the validity of the token yet, but that's a start already. +
+ ++ 看到了吧,只要多写三四行代码,就可以添加基础的安全表单。 +
diff --git a/docs/zh/docs/tutorial/security/get-current-user.md b/docs/zh/docs/tutorial/security/get-current-user.md index 477baec3afbf4..c503a34059ba5 100644 --- a/docs/zh/docs/tutorial/security/get-current-user.md +++ b/docs/zh/docs/tutorial/security/get-current-user.md @@ -2,24 +2,73 @@ 在上一章节中,(基于依赖项注入系统的)安全系统向*路径操作函数*提供了一个 `str` 类型的 `token`: -```Python hl_lines="10" -{!../../../docs_src/security/tutorial001.py!} -``` +=== "Python 3.9+" + + ```Python hl_lines="12" + 这些内容在下一章节。 + ``` + +=== "Python 3.6+" + + ```Python hl_lines="11" + !!! tip + 你可能还记得请求体也是使用 Pydantic 模型来声明的。 + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="10" + {!../../../docs_src/security/tutorial002.py!} + ``` 但这还不是很实用。 让我们来使它返回当前用户给我们。 - ## 创建一个用户模型 首先,让我们来创建一个用户 Pydantic 模型。 与使用 Pydantic 声明请求体的方式相同,我们可以在其他任何地方使用它: -```Python hl_lines="5 12-16" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.10+" + + ```Python hl_lines="5 12-16" + {!> ../../../docs_src/security/tutorial002_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="5 12-16" + {!> ../../../docs_src/security/tutorial002_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="5 13-17" + {!> ../../../docs_src/security/tutorial002_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="3 10-14" + {!../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="5 12-16" + {!../../../docs_src/security/tutorial001.py!} + ``` ## 创建一个 `get_current_user` 依赖项 @@ -31,41 +80,139 @@ 与我们之前直接在路径操作中所做的相同,我们新的依赖项 `get_current_user` 将从子依赖项 `oauth2_scheme` 中接收一个 `str` 类型的 `token`: -```Python hl_lines="25" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.10+" + + ```Python hl_lines="25" + {!> ../../../docs_src/security/tutorial002_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="25" + {!> ../../../docs_src/security/tutorial002_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="26" + {!> ../../../docs_src/security/tutorial002_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="23" + {!../../../docs_src/security/tutorial002.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="25" + {!../../../docs_src/security/tutorial002.py!} + ``` ## 获取用户 `get_current_user` 将使用我们创建的(伪)工具函数,该函数接收 `str` 类型的令牌并返回我们的 Pydantic `User` 模型: -```Python hl_lines="19-22 26-27" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.10+" + + ```Python hl_lines="19-22 26-27" + {!> ../../../docs_src/security/tutorial002_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="19-22 26-27" + {!> ../../../docs_src/security/tutorial002_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="20-23 27-28" + {!> ../../../docs_src/security/tutorial002_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="17-20 24-25" + {!> ../../../docs_src/security/tutorial002_py310.py!} + ``` + +=== "Python 3.6+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="19-22 26-27" + {!> ../../../docs_src/security/tutorial002.py!} + ``` ## 注入当前用户 因此现在我们可以在*路径操作*中使用 `get_current_user` 作为 `Depends` 了: -```Python hl_lines="31" -{!../../../docs_src/security/tutorial002.py!} -``` +=== "Python 3.10+" + + ```Python hl_lines="31" + {!> ../../../docs_src/security/tutorial002_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="31" + {!> ../../../docs_src/security/tutorial002_an_py39.py!} + ``` + +=== "Python 3.6+" + + ```Python hl_lines="32" + !!! check + 这种依赖系统的设计方式使我们可以拥有不同的依赖项(不同的「可依赖类型」),并且它们都返回一个User 模型。
+ ```
+ 模型。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="29"
+ {!> ../../../docs_src/security/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="31"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
注意我们将 `current_user` 的类型声明为 Pydantic 模型 `User`。
这将帮助我们在函数内部使用所有的代码补全和类型检查。
!!! tip
- 你可能还记得请求体也是使用 Pydantic 模型来声明的。
+ You might remember that request bodies are also declared with Pydantic models.
在这里 **FastAPI** 不会搞混,因为你正在使用的是 `Depends`。
!!! check
- 这种依赖系统的设计方式使我们可以拥有不同的依赖项(不同的「可依赖类型」),并且它们都返回一个 `User` 模型。
+ The way this dependency system is designed allows us to have different dependencies (different "dependables") that all return a `User` model.
我们并未被局限于只能有一个返回该类型数据的依赖项。
-
## 其他模型
现在你可以直接在*路径操作函数*中获取当前用户,并使用 `Depends` 在**依赖注入**级别处理安全性机制。
@@ -74,24 +221,23 @@
但是你并未被限制只能使用某些特定的数据模型,类或类型。
-你想要在模型中使用 `id` 和 `email` 而不使用任何的 `username`?当然可以。你可以同样地使用这些工具。
+你想要在模型中使用 `id` 和 `email` 而不使用任何的 `username`? 当然可以。 你可以同样地使用这些工具。
-你只想要一个 `str`?或者仅仅一个 `dict`?还是直接一个数据库模型类的实例?它们的工作方式都是一样的。
+你只想要一个 `str`? 或者仅仅一个 `dict`? 还是直接一个数据库模型类的实例? 它们的工作方式都是一样的。
-实际上你没有用户登录到你的应用程序,而是只拥有访问令牌的机器人,程序或其他系统?再一次,它们的工作方式也是一样的。
-
-尽管去使用你的应用程序所需要的任何模型,任何类,任何数据库。**FastAPI** 通过依赖项注入系统都帮你搞定。
+实际上你没有用户登录到你的应用程序,而是只拥有访问令牌的机器人,程序或其他系统? 再一次,它们的工作方式也是一样的。
+尽管去使用你的应用程序所需要的任何模型,任何类,任何数据库。 **FastAPI** 通过依赖项注入系统都帮你搞定。
## 代码体积
-这个示例似乎看起来很冗长。考虑到我们在同一文件中混合了安全性,数据模型工具函数和路径操作等代码。
+这个示例似乎看起来很冗长。 考虑到我们在同一文件中混合了安全性,数据模型工具函数和路径操作等代码。
但关键的是。
安全性和依赖项注入内容只需要编写一次。
-你可以根据需要使其变得很复杂。而且只需要在一个地方写一次。但仍然具备所有的灵活性。
+你可以根据需要使其变得很复杂。 而且只需要在一个地方写一次。 但仍然具备所有的灵活性。
但是,你可以有无数个使用同一安全系统的端点(*路径操作*)。
@@ -99,11 +245,43 @@
所有的这无数个*路径操作*甚至可以小到只需 3 行代码:
-```Python hl_lines="30-32"
-{!../../../docs_src/security/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="30-32"
+ 总结
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="30-32"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="31-33"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="28-30"
+ {!> ../../../docs_src/security/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="30-32"
+ {!../../../docs_src/security/tutorial002.py!}
+ ```
-## 总结
+## Recap
现在你可以直接在*路径操作函数*中获取当前用户。
@@ -111,4 +289,4 @@
我们只需要再为用户/客户端添加一个真正发送 `username` 和 `password` 的*路径操作*。
-这些内容在下一章节。
+That comes next.
diff --git a/docs/zh/docs/tutorial/security/index.md b/docs/zh/docs/tutorial/security/index.md
index 0595f5f636129..b4b26eb0e49a9 100644
--- a/docs/zh/docs/tutorial/security/index.md
+++ b/docs/zh/docs/tutorial/security/index.md
@@ -10,7 +10,7 @@
但首先,让我们来看一些小的概念。
-## 没有时间?
+## In a hurry?
如果你不关心这些术语,而只需要*立即*通过基于用户名和密码的身份认证来增加安全性,请跳转到下一章。
@@ -32,7 +32,7 @@ OAuth2是一个规范,它定义了几种处理身份认证和授权的方法
OAuth2 没有指定如何加密通信,它期望你为应用程序使用 HTTPS 进行通信。
-!!! tip
+!!! !!! tip
在有关**部署**的章节中,你将了解如何使用 Traefik 和 Let's Encrypt 免费设置 HTTPS。
@@ -44,11 +44,11 @@ OpenID Connect 是另一个基于 **OAuth2** 的规范。
例如,Google 登录使用 OpenID Connect(底层使用OAuth2)。
-但是 Facebook 登录不支持 OpenID Connect。它具有自己的 OAuth2 风格。
+但是 Facebook 登录不支持 OpenID Connect。 它具有自己的 OAuth2 风格。
### OpenID(非「OpenID Connect」)
-还有一个「OpenID」规范。它试图解决与 **OpenID Connect** 相同的问题,但它不是基于 OAuth2。
+还有一个「OpenID」规范。 它试图解决与 **OpenID Connect** 相同的问题,但它不是基于 OAuth2。
因此,它是一个完整的附加系统。
@@ -70,14 +70,14 @@ OpenAPI 定义了以下安全方案:
* `apiKey`:一个特定于应用程序的密钥,可以来自:
* 查询参数。
- * 请求头。
+ * A header.
* cookie。
* `http`:标准的 HTTP 身份认证系统,包括:
- * `bearer`: 一个值为 `Bearer` 加令牌字符串的 `Authorization` 请求头。这是从 OAuth2 继承的。
+ * `bearer`: 一个值为 `Bearer` 加令牌字符串的 `Authorization` 请求头。 这是从 OAuth2 继承的。
* HTTP Basic 认证方式。
* HTTP Digest,等等。
* `oauth2`:所有的 OAuth2 处理安全性的方式(称为「流程」)。
- *以下几种流程适合构建 OAuth 2.0 身份认证的提供者(例如 Google,Facebook,Twitter,GitHub 等):
+ * *以下几种流程适合构建 OAuth 2.0 身份认证的提供者(例如 Google,Facebook,Twitter,GitHub 等): * `implicit` * `clientCredentials` * `authorizationCode`
* `implicit`
* `clientCredentials`
* `authorizationCode`
@@ -87,7 +87,7 @@ OpenAPI 定义了以下安全方案:
* 此自动发现机制是 OpenID Connect 规范中定义的内容。
-!!! tip
+!!! !!! tip
集成其他身份认证/授权提供者(例如Google,Facebook,Twitter,GitHub等)也是可能的,而且较为容易。
最复杂的问题是创建一个像这样的身份认证/授权提供程序,但是 **FastAPI** 为你提供了轻松完成任务的工具,同时为你解决了重活。
diff --git a/docs/zh/docs/tutorial/security/oauth2-jwt.md b/docs/zh/docs/tutorial/security/oauth2-jwt.md
index 054198545ef8e..7e126a75d93d3 100644
--- a/docs/zh/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/zh/docs/tutorial/security/oauth2-jwt.md
@@ -4,25 +4,25 @@
本章的示例代码真正实现了在应用的数据库中保存哈希密码等功能。
-接下来,我们紧接上一章,继续完善安全机制。
+We are going to start from where we left in the previous chapter and increment it.
## JWT 简介
JWT 即**JSON 网络令牌**(JSON Web Tokens)。
-JWT 是一种将 JSON 对象编码为没有空格,且难以理解的长字符串的标准。JWT 的内容如下所示:
+JWT 是一种将 JSON 对象编码为没有空格,且难以理解的长字符串的标准。 It looks like this:
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```
-JWT 字符串没有加密,任何人都能用它恢复原始信息。
+It is not encrypted, so, anyone could recover the information from the contents.
-但 JWT 使用了签名机制。接受令牌时,可以用签名校验令牌。
+But it's signed. So, when you receive a token that you emitted, you can verify that you actually emitted it.
-使用 JWT 创建有效期为一周的令牌。第二天,用户持令牌再次访问时,仍为登录状态。
+使用 JWT 创建有效期为一周的令牌。 第二天,用户持令牌再次访问时,仍为登录状态。
-令牌于一周后过期,届时,用户身份验证就会失败。只有再次登录,才能获得新的令牌。如果用户(或第三方)篡改令牌的过期时间,因为签名不匹配会导致身份验证失败。
+After a week, the token will be expired and the user will not be authorized and will have to sign in again to get a new token. 如果用户(或第三方)篡改令牌的过期时间,因为签名不匹配会导致身份验证失败。
如需深入了解 JWT 令牌,了解它的工作方式,请参阅 https://jwt.io。
@@ -44,15 +44,13 @@ $ pip install python-jose[cryptography]
本教程推荐的后端是:pyca/cryptography。
-!!! tip "提示"
-
- 本教程以前使用 PyJWT。
+!!! 本教程以前使用 <a href="https://pyjwt.readthedocs.io/" class="external-link" target="_blank">PyJWT</a>。
但后来换成了 Python-jose,因为 Python-jose 支持 PyJWT 的所有功能,还支持与其它工具集成时可能会用到的一些其它功能。
## 密码哈希
-**哈希**是指把特定内容(本例中为密码)转换为乱码形式的字节序列(其实就是字符串)。
+"Hashing" means converting some content (a password in this case) into a sequence of bytes (just a string) that looks like gibberish.
每次传入完全相同的内容时(比如,完全相同的密码),返回的都是完全相同的乱码。
@@ -60,7 +58,7 @@ $ pip install python-jose[cryptography]
### 为什么使用密码哈希
-原因很简单,假如数据库被盗,窃贼无法获取用户的明文密码,得到的只是哈希值。
+If your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.
这样一来,窃贼就无法在其它应用中使用窃取的密码,要知道,很多用户在所有系统中都使用相同的密码,风险超大)。
@@ -70,7 +68,7 @@ Passlib 是处理密码哈希的 Python 包。
它支持很多安全哈希算法及配套工具。
-本教程推荐的算法是 **Bcrypt**。
+The recommended algorithm is "Bcrypt".
因此,请先安装附带 Bcrypt 的 PassLib:
@@ -84,41 +82,68 @@ $ pip install passlib[bcrypt]
-!!! tip "提示"
-
- `passlib` 甚至可以读取 Django、Flask 的安全插件等工具创建的密码。
-
- 例如,把 Django 应用的数据共享给 FastAPI 应用的数据库。或利用同一个数据库,可以逐步把应用从 Django 迁移到 FastAPI。
+!!! `passlib` 甚至可以读取 Django、Flask 的安全插件等工具创建的密码。
+ 例如,把 Django 应用的数据共享给 FastAPI 应用的数据库。 或利用同一个数据库,可以逐步把应用从 Django 迁移到 FastAPI。
+
并且,用户可以同时从 Django 应用或 FastAPI 应用登录。
## 密码哈希与校验
从 `passlib` 导入所需工具。
-创建用于密码哈希和身份校验的 PassLib **上下文**。
+Create a PassLib "context". This is what will be used to hash and verify passwords.
-!!! tip "提示"
-
- PassLib 上下文还支持使用不同哈希算法的功能,包括只能校验的已弃用旧算法等。
+!!! PassLib 上下文还支持使用不同哈希算法的功能,包括只能校验的已弃用旧算法等。
例如,用它读取和校验其它系统(如 Django)生成的密码,但要使用其它算法,如 Bcrypt,生成新的哈希密码。
-
+
同时,这些功能都是兼容的。
接下来,创建三个工具函数,其中一个函数用于哈希用户的密码。
-第一个函数用于校验接收的密码是否匹配存储的哈希值。
+And another utility to verify if a received password matches the hash stored.
第三个函数用于身份验证,并返回用户。
-```Python hl_lines="7 48 55-56 59-60 69-75"
-{!../../../docs_src/security/tutorial004.py!}
-```
+=== "Python 3.10+"
-!!! note "笔记"
+ ```Python hl_lines="7 48 55-56 59-60 69-75"
+ !!! tip "提示"
+ ```
- 查看新的(伪)数据库 `fake_users_db`,就能看到哈希后的密码:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`。
+=== "Python 3.9+"
+
+ ```Python hl_lines="7 48 55-56 59-60 69-75"
+ 接下来,我们紧接上一章,继续完善安全机制。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="7 49 56-57 60-61 70-76"
+ 而且,FastAPI 还提供了一些工具,在不影响灵活、稳定和安全的前提下,尽可能地简化安全机制。
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6 47 54-55 58-59 68-74"
+ 原因很简单,假如数据库被盗,窃贼无法获取用户的明文密码,得到的只是哈希值。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 48 55-56 59-60 69-75"
+ {!../../../docs_src/security/tutorial004.py!}
+ ```
+
+!!! note
+ If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
## 处理 JWT 令牌
@@ -148,9 +173,41 @@ $ openssl rand -hex 32
创建生成新的访问令牌的工具函数。
-```Python hl_lines="6 12-14 28-30 78-86"
-{!../../../docs_src/security/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="6 12-14 28-30 78-86"
+ 注意,代码中没有明文密码**`secret`**,只保存了它的哈希值。
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="6 12-14 28-30 78-86"
+ FastAPI 还支持以相对简单的方式,使用 OAuth2 等安全、标准的协议。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="6 13-15 29-31 79-87"
+ 注意,请求中 `Authorization` 响应头的值以 `Bearer` 开头。
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="5 11-13 27-29 77-85"
+ 第一个函数用于校验接收的密码是否匹配存储的哈希值。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6 12-14 28-30 78-86"
+ {!../../../docs_src/security/tutorial004.py!}
+ ```
## 更新依赖项
@@ -160,9 +217,41 @@ $ openssl rand -hex 32
如果令牌无效,则直接返回 HTTP 错误。
-```Python hl_lines="89-106"
-{!../../../docs_src/security/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="89-106"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="89-106"
+ 本教程推荐的算法是 Bcrypt。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="90-107"
+ 开发者可以灵活选择最适合项目的安全机制。
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="88-105"
+ 创建用于密码哈希和身份校验的 PassLib 上下文。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="89-106"
+ {!../../../docs_src/security/tutorial004.py!}
+ ```
## 更新 `/token` *路径操作*
@@ -170,9 +259,43 @@ $ openssl rand -hex 32
创建并返回真正的 JWT 访问令牌。
-```Python hl_lines="115-128"
-{!../../../docs_src/security/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="117-132"
+ !!! tip "提示"
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="117-132"
+ !!! check "检查"
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="118-133"
+ OAuth2 支持scopes(作用域)。
+ ```
+(作用域)。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="114-127"
+ 查看新的(伪)数据库 `fake_users_db`,就能看到哈希后的密码:`"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="115-128"
+ {!../../../docs_src/security/tutorial004.py!}
+ ```
### JWT `sub` 的技术细节
@@ -182,17 +305,17 @@ JWT 规范还包括 `sub` 键,值是令牌的主题。
除了识别用户与许可用户在 API 上直接执行操作之外,JWT 还可能用于其它事情。
-例如,识别**汽车**或**博客**。
+For example, you could identify a "car" or a "blog post".
-接着,为实体添加权限,比如**驾驶**(汽车)或**编辑**(博客)。
+Then you could add permissions about that entity, like "drive" (for the car) or "edit" (for the blog).
-然后,把 JWT 令牌交给用户(或机器人),他们就可以执行驾驶汽车,或编辑博客等操作。无需注册账户,只要有 API 生成的 JWT 令牌就可以。
+JWT 字符串没有加密,任何人都能用它恢复原始信息。
同理,JWT 可以用于更复杂的场景。
在这些情况下,多个实体的 ID 可能是相同的,以 ID `foo` 为例,用户的 ID 是 `foo`,车的 ID 是 `foo`,博客的 ID 也是 `foo`。
-为了避免 ID 冲突,在给用户创建 JWT 令牌时,可以为 `sub` 键的值加上前缀,例如 `username:`。因此,在本例中,`sub` 的值可以是:`username:johndoe`。
+为了避免 ID 冲突,在给用户创建 JWT 令牌时,可以为 `sub` 键的值加上前缀,例如 `username:`。 因此,在本例中,`sub` 的值可以是:`username:johndoe`。
注意,划重点,`sub` 键在整个应用中应该只有一个唯一的标识符,而且应该是字符串。
@@ -202,7 +325,7 @@ JWT 规范还包括 `sub` 键,值是令牌的主题。
可以看到如下用户界面:
-
+
用与上一章同样的方式实现应用授权。
@@ -210,11 +333,10 @@ JWT 规范还包括 `sub` 键,值是令牌的主题。
用户名: `johndoe` 密码: `secret`
-!!! check "检查"
+!!! check
+ Notice that nowhere in the code is the plaintext password "`secret`", we only have the hashed version.
- 注意,代码中没有明文密码**`secret`**,只保存了它的哈希值。
-
-
+
调用 `/users/me/` 端点,收到下面的响应:
@@ -227,44 +349,43 @@ JWT 规范还包括 `sub` 键,值是令牌的主题。
}
```
-
+
打开浏览器的开发者工具,查看数据是怎么发送的,而且数据里只包含了令牌,只有验证用户的第一个请求才发送密码,并获取访问令牌,但之后不会再发送密码:
-
-
-!!! note "笔记"
+
- 注意,请求中 `Authorization` 响应头的值以 `Bearer` 开头。
+!!! note
+ Notice the header `Authorization`, with a value that starts with `Bearer`.
## `scopes` 高级用法
-OAuth2 支持**`scopes`**(作用域)。
+OAuth2 has the notion of "scopes".
-**`scopes`**为 JWT 令牌添加指定权限。
+You can use them to add a specific set of permissions to a JWT token.
让持有令牌的用户或第三方在指定限制条件下与 API 交互。
**高级用户指南**中将介绍如何使用 `scopes`,及如何把 `scopes` 集成至 **FastAPI**。
-## 小结
+## Recap
至此,您可以使用 OAuth2 和 JWT 等标准配置安全的 **FastAPI** 应用。
几乎在所有框架中,处理安全问题很快都会变得非常复杂。
-有些包为了简化安全流,不得不在数据模型、数据库和功能上做出妥协。而有些过于简化的软件包其实存在了安全隐患。
+有些包为了简化安全流,不得不在数据模型、数据库和功能上做出妥协。 而有些过于简化的软件包其实存在了安全隐患。
---
**FastAPI** 不向任何数据库、数据模型或工具做妥协。
-开发者可以灵活选择最适合项目的安全机制。
+It gives you all the flexibility to choose the ones that fit your project the best.
还可以直接使用 `passlib` 和 `python-jose` 等维护良好、使用广泛的包,这是因为 **FastAPI** 不需要任何复杂机制,就能集成外部的包。
-而且,**FastAPI** 还提供了一些工具,在不影响灵活、稳定和安全的前提下,尽可能地简化安全机制。
+But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security.
-**FastAPI** 还支持以相对简单的方式,使用 OAuth2 等安全、标准的协议。
+And you can use and implement secure, standard protocols, like OAuth2 in a relatively simple way.
-**高级用户指南**中详细介绍了 OAuth2**`scopes`**的内容,遵循同样的标准,实现更精密的权限系统。OAuth2 的作用域是脸书、谷歌、GitHub、微软、推特等第三方身份验证应用使用的机制,让用户授权第三方应用与 API 交互。
+**高级用户指南**中详细介绍了 OAuth2**`scopes`**的内容,遵循同样的标准,实现更精密的权限系统。 OAuth2 的作用域是脸书、谷歌、GitHub、微软、推特等第三方身份验证应用使用的机制,让用户授权第三方应用与 API 交互。
diff --git a/docs/zh/docs/tutorial/security/simple-oauth2.md b/docs/zh/docs/tutorial/security/simple-oauth2.md
index 276f3d63b69f9..7b782c9e1bd33 100644
--- a/docs/zh/docs/tutorial/security/simple-oauth2.md
+++ b/docs/zh/docs/tutorial/security/simple-oauth2.md
@@ -8,7 +8,7 @@
OAuth2 规定在使用(我们打算用的)「password 流程」时,客户端/用户必须将 `username` 和 `password` 字段作为表单数据发送。
-而且规范明确了字段必须这样命名。因此 `user-name` 或 `email` 是行不通的。
+而且规范明确了字段必须这样命名。 因此 `user-name` 或 `email` 是行不通的。
不过不用担心,你可以在前端按照你的想法将它展示给最终用户。
@@ -24,7 +24,7 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
这个表单字段的名称为 `scope`(单数形式),但实际上它是一个由空格分隔的「作用域」组成的长字符串。
-每个「作用域」只是一个字符串(中间没有空格)。
+Each "scope" is just a string (without spaces).
它们通常用于声明特定的安全权限,例如:
@@ -33,12 +33,12 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
* Google 使用了 `https://www.googleapis.com/auth/drive` 。
!!! info
- 在 OAuth2 中「作用域」只是一个声明所需特定权限的字符串。
+ In OAuth2 a "scope" is just a string that declares a specific permission required.
它有没有 `:` 这样的其他字符或者是不是 URL 都没有关系。
-
+
这些细节是具体的实现。
-
+
对 OAuth2 来说它们就只是字符串而已。
## 获取 `username` 和 `password` 的代码
@@ -49,9 +49,45 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
首先,导入 `OAuth2PasswordRequestForm`,然后在 `token` 的*路径操作*中通过 `Depends` 将其作为依赖项使用。
-```Python hl_lines="4 76"
-{!../../../docs_src/security/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="4 78"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 78"
+ !!! tip
+ 在下一章中,你将看到一个真实的安全实现,使用了哈希密码和 JWT 令牌。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4 79"
+ !!! info
+ OAuth2PasswordRequestForm 并不像 OAuth2PasswordBearer 一样是 FastAPI 的一个特殊的类。
+ ```
+ 并不像 OAuth2PasswordBearer 一样是 FastAPI 的一个特殊的类。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 74"
+ 如果没有这个用户,我们将返回一个错误消息,提示「用户名或密码错误」。
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 76"
+ {!../../../docs_src/security/tutorial003.py!}
+ ```
`OAuth2PasswordRequestForm` 是一个类依赖项,声明了如下的请求表单:
@@ -61,7 +97,7 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
* 一个可选的 `grant_type`.
!!! tip
- OAuth2 规范实际上*要求* `grant_type` 字段使用一个固定的值 `password`,但是 `OAuth2PasswordRequestForm` 没有作强制约束。
+ The OAuth2 spec actually *requires* a field `grant_type` with a fixed value of `password`, but `OAuth2PasswordRequestForm` doesn't enforce it.
如果你需要强制要求这一点,请使用 `OAuth2PasswordRequestFormStrict` 而不是 `OAuth2PasswordRequestForm`。
@@ -69,30 +105,66 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
* 一个可选的 `client_secret`(我们的示例不需要它)。
!!! info
- `OAuth2PasswordRequestForm` 并不像 `OAuth2PasswordBearer` 一样是 FastAPI 的一个特殊的类。
-
- `OAuth2PasswordBearer` 使得 **FastAPI** 明白它是一个安全方案。所以它得以通过这种方式添加到 OpenAPI 中。
+ The `OAuth2PasswordRequestForm` is not a special class for **FastAPI** as is `OAuth2PasswordBearer`.
+ `OAuth2PasswordBearer` 使得 **FastAPI** 明白它是一个安全方案。 所以它得以通过这种方式添加到 OpenAPI 中。
+
但 `OAuth2PasswordRequestForm` 只是一个你可以自己编写的类依赖项,或者你也可以直接声明 `Form` 参数。
-
+
但是由于这是一种常见的使用场景,因此 FastAPI 出于简便直接提供了它。
### 使用表单数据
!!! tip
- 类依赖项 `OAuth2PasswordRequestForm` 的实例不会有用空格分隔的长字符串属性 `scope`,而是具有一个 `scopes` 属性,该属性将包含实际被发送的每个作用域字符串组成的列表。
+ The instance of the dependency class `OAuth2PasswordRequestForm` won't have an attribute `scope` with the long string separated by spaces, instead, it will have a `scopes` attribute with the actual list of strings for each scope sent.
在此示例中我们没有使用 `scopes`,但如果你需要的话可以使用该功能。
现在,使用表单字段中的 `username` 从(伪)数据库中获取用户数据。
-如果没有这个用户,我们将返回一个错误消息,提示「用户名或密码错误」。
+如果密码不匹配,我们将返回同一个错误。
对于这个错误,我们使用 `HTTPException` 异常:
-```Python hl_lines="3 77-79"
-{!../../../docs_src/security/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="3 79-81"
+ !!! info
+ 我们在此处返回的值为 Bearer 的额外响应头 WWW-Authenticate 也是规范的一部分。
+ ```
+ 的额外响应头 WWW-Authenticate 也是规范的一部分。
+
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3 79-81"
+ https://fastapi.tiangolo.com/img/tutorial/security/image05.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3 80-82"
+ !!! info
+ 在 OAuth2 中「作用域」只是一个声明所需特定权限的字符串。
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1 75-77"
+ {!../../../docs_src/security/tutorial003.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3 77-79"
+ {!../../../docs_src/security/tutorial003.py!}
+ ```
### 校验密码
@@ -102,7 +174,7 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
永远不要保存明文密码,因此,我们将使用(伪)哈希密码系统。
-如果密码不匹配,我们将返回同一个错误。
+If the passwords don't match, we return the same error.
#### 哈希密码
@@ -118,9 +190,44 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
因此,小偷将无法尝试在另一个系统中使用这些相同的密码(由于许多用户在任何地方都使用相同的密码,因此这很危险)。
-```Python hl_lines="80-83"
-{!../../../docs_src/security/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="82-85"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="82-85"
+ https://fastapi.tiangolo.com/img/tutorial/security/image04.png
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="83-86"
+ !!! tip
+ OAuth2 规范实际上要求 grant_type 字段使用一个固定的值 password,但是 OAuth2PasswordRequestForm 没有作强制约束。
+ ```
+ 字段使用一个固定的值 password,但是 OAuth2PasswordRequestForm 没有作强制约束。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="78-81"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="80-83"
+ {!../../../docs_src/security/tutorial003.py!}
+ ```
#### 关于 `**user_dict`
@@ -139,34 +246,69 @@ UserInDB(
```
!!! info
- 有关 `user_dict` 的更完整说明,请参阅[**额外的模型**文档](../extra-models.md#about-user_indict){.internal-link target=_blank}。
+ For a more complete explanation of `**user_dict` check back in [the documentation for **Extra Models**](../extra-models.md#about-user_indict){.internal-link target=_blank}.
## 返回令牌
`token` 端点的响应必须是一个 JSON 对象。
-它应该有一个 `token_type`。在我们的例子中,由于我们使用的是「Bearer」令牌,因此令牌类型应为「`bearer`」。
+它应该有一个 `token_type`。 在我们的例子中,由于我们使用的是「Bearer」令牌,因此令牌类型应为「`bearer`」。
并且还应该有一个 `access_token` 字段,它是一个包含我们的访问令牌的字符串。
对于这个简单的示例,我们将极其不安全地返回相同的 `username` 作为令牌。
!!! tip
- 在下一章中,你将看到一个真实的安全实现,使用了哈希密码和 JWT 令牌。
+ In the next chapter, you will see a real secure implementation, with password hashing and JWT tokens.
但现在,让我们仅关注我们需要的特定细节。
-```Python hl_lines="85"
-{!../../../docs_src/security/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="87"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="87"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="88"
+ !!! info
+ 有关 user_dict 的更完整说明,请参阅额外的模型文档{.internal-link target=_blank}。
+ ```
+ 的更完整说明,请参阅[**额外的模型**文档](../extra-models.md#about-user_indict){.internal-link target=_blank}。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="83"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="85"
+ {!../../../docs_src/security/tutorial003.py!}
+ ```
!!! tip
- 根据规范,你应该像本示例一样,返回一个带有 `access_token` 和 `token_type` 的 JSON。
+ By the spec, you should return a JSON with an `access_token` and a `token_type`, the same as in this example.
这是你必须在代码中自行完成的工作,并且要确保使用了这些 JSON 字段。
-
+
这几乎是唯一的你需要自己记住并正确地执行以符合规范的事情。
-
+
其余的,**FastAPI** 都会为你处理。
## 更新依赖项
@@ -181,26 +323,64 @@ UserInDB(
因此,在我们的端点中,只有当用户存在,身份认证通过且处于启用状态时,我们才能获得该用户:
-```Python hl_lines="58-67 69-72 90"
-{!../../../docs_src/security/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="58-66 69-74 94"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="58-66 69-74 94"
+ 每个「作用域」只是一个字符串(中间没有空格)。
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="59-67 70-75 95"
+ !!! tip
+ 类依赖项 OAuth2PasswordRequestForm 的实例不会有用空格分隔的长字符串属性 scope,而是具有一个 scopes 属性,该属性将包含实际被发送的每个作用域字符串组成的列表。
+ ```
+ 的实例不会有用空格分隔的长字符串属性 scope,而是具有一个 scopes 属性,该属性将包含实际被发送的每个作用域字符串组成的列表。
+
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="56-64 67-70 88"
+ {!> ../../../docs_src/security/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="58-66 69-72 90"
+ !!! tip
+ 根据规范,你应该像本示例一样,返回一个带有 access_token 和 token_type 的 JSON。
+ ```
+ 和 token_type 的 JSON。
+
!!! info
- 我们在此处返回的值为 `Bearer` 的额外响应头 `WWW-Authenticate` 也是规范的一部分。
+ The additional header `WWW-Authenticate` with value `Bearer` we are returning here is also part of the spec.
任何的 401「未认证」HTTP(错误)状态码都应该返回 `WWW-Authenticate` 响应头。
-
+
对于 bearer 令牌(我们的例子),该响应头的值应为 `Bearer`。
-
+
实际上你可以忽略这个额外的响应头,不会有什么问题。
-
+
但此处提供了它以符合规范。
-
+
而且,(现在或将来)可能会有工具期望得到并使用它,然后对你或你的用户有用处。
-
+
这就是遵循标准的好处...
-## 实际效果
+## See it in action
打开交互式文档:http://127.0.0.1:8000/docs。
@@ -214,11 +394,11 @@ UserInDB(
密码:`secret`
-
+
在系统中进行身份认证后,你将看到:
-
+
### 获取本人的用户数据
@@ -236,7 +416,7 @@ UserInDB(
}
```
-
+
如果你点击锁定图标并注销,然后再次尝试同一操作,则会得到 HTTP 401 错误:
@@ -264,7 +444,7 @@ UserInDB(
}
```
-## 总结
+## Recap
现在你掌握了为你的 API 实现一个基于 `username` 和 `password` 的完整安全系统的工具。
diff --git a/docs/zh/docs/tutorial/sql-databases.md b/docs/zh/docs/tutorial/sql-databases.md
index 482588f94d7ec..53de41a7bd3c2 100644
--- a/docs/zh/docs/tutorial/sql-databases.md
+++ b/docs/zh/docs/tutorial/sql-databases.md
@@ -1,5 +1,12 @@
# SQL (关系型) 数据库
+!!! info
+ These docs are about to be updated. 🎉
+
+ The current version assumes Pydantic v1, and SQLAlchemy versions less than 2.0.
+
+ The new docs will include Pydantic v2 and will use SQLModel (which is also based on SQLAlchemy) once it is updated to use Pydantic v2 as well.
+
**FastAPI**不需要你使用SQL(关系型)数据库。
但是您可以使用任何您想要的关系型数据库。
@@ -14,17 +21,19 @@
* Oracle
* Microsoft SQL Server,等等其它数据库
-在此示例中,我们将使用**SQLite**,因为它使用单个文件并且 在Python中具有集成支持。因此,您可以复制此示例并按原样来运行它。
+在此示例中,我们将使用**SQLite**,因为它使用单个文件并且 在Python中具有集成支持。 因此,您可以复制此示例并按原样来运行它。
稍后,对于您的产品级别的应用程序,您可能会要使用像**PostgreSQL**这样的数据库服务器。
-!!! tip
+!!! !!! tip
这儿有一个**FastAPI**和**PostgreSQL**的官方项目生成器,全部基于**Docker**,包括前端和更多工具:https://github.com/tiangolo/full-stack-fastapi-postgresql
-!!! note
- 请注意,大部分代码是`SQLAlchemy`的标准代码,您可以用于任何框架。FastAPI特定的代码和往常一样少。
+!!! !!! note
+ 请注意,大部分代码是`SQLAlchemy`的标准代码,您可以用于任何框架。
-## ORMs(对象关系映射)
+ FastAPI特定的代码和往常一样少。
+
+## ORMs
**FastAPI**可与任何数据库在任何样式的库中一起与 数据库进行通信。
@@ -36,19 +45,19 @@ ORM 具有在代码和数据库表(“*关系型”)中的**对象**之间
例如,一个类`Pet`可以表示一个 SQL 表`pets`。
-该类的每个*实例对象都代表数据库中的一行数据。*
+And each *instance* object of that class represents a row in the database.
-又例如,一个对象`orion_cat`(`Pet`的一个实例)可以有一个属性`orion_cat.type`, 对标数据库中的`type`列。并且该属性的值可以是其它,例如`"cat"`。
+又例如,一个对象`orion_cat`(`Pet`的一个实例)可以有一个属性`orion_cat.type`, 对标数据库中的`type`列。 并且该属性的值可以是其它,例如`"cat"`。
这些 ORM 还具有在表或实体之间建立关系的工具(比如创建多表关系)。
-这样,您还可以拥有一个属性`orion_cat.owner`,它包含该宠物所有者的数据,这些数据取自另外一个表。
-
因此,`orion_cat.owner.name`可能是该宠物主人的姓名(来自表`owners`中的列`name`)。
+这样,您还可以拥有一个属性`orion_cat.owner`,它包含该宠物所有者的数据,这些数据取自另外一个表。
+
它可能有一个像`"Arquilian"`(一种业务逻辑)。
-当您尝试从您的宠物对象访问它时,ORM 将完成所有工作以从相应的表*所有者那里再获取信息。*
+当您尝试从您的宠物对象访问它时,ORM 将完成所有工作以从相应的表*所有者那里再获取信息。
常见的 ORM 例如:Django-ORM(Django 框架的一部分)、SQLAlchemy ORM(SQLAlchemy 的一部分,独立于框架)和 Peewee(独立于框架)等。
@@ -56,7 +65,7 @@ ORM 具有在代码和数据库表(“*关系型”)中的**对象**之间
以类似的方式,您也可以使用任何其他 ORM。
-!!! tip
+!!! !!! tip
在文档中也有一篇使用 Peewee 的等效的文章。
## 文件结构
@@ -65,6 +74,7 @@ ORM 具有在代码和数据库表(“*关系型”)中的**对象**之间
```
.
+.
└── sql_app
├── __init__.py
├── crud.py
@@ -78,9 +88,24 @@ ORM 具有在代码和数据库表(“*关系型”)中的**对象**之间
现在让我们看看每个文件/模块的作用。
+## Install `SQLAlchemy`
+
+!!! tip
+ SQLAlchemy 模型`User`包含一个`hashed_password`,它应该是一个包含散列的安全密码。
+
+
-
-## 直接与数据库交互
-
-如果您想独立于 FastAPI 直接浏览 SQLite 数据库(文件)以调试其内容、添加表、列、记录、修改数据等,您可以使用[SQLite 的 DB Browser](https://sqlitebrowser.org/)
-
-它看起来像这样:
-
-
-
-您还可以使用[SQLite Viewer](https://inloop.github.io/sqlite-viewer/)或[ExtendsClass](https://extendsclass.com/sqlite-browser.html)等在线 SQLite 浏览器。
-
-## 中间件替代数据库会话
-
-如果你不能使用依赖项`yield`——例如,如果你没有使用**Python 3.7**并且不能安装上面提到的**Python 3.6**的“backports” ——你可以在类似的“中间件”中设置会话方法。
-
-“中间件”基本功能是一个为每个请求执行的函数在请求之前进行执行相应的代码,以及在请求执行之后执行相应的代码。
-
-### 创建中间件
-
-我们将添加中间件(只是一个函数)将为每个请求创建一个新的 SQLAlchemy`SessionLocal`,将其添加到请求中,然后在请求完成后关闭它。
-
-=== "Python 3.9+"
-
- ```Python hl_lines="12-20"
- {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
- ```
-
-=== "Python 3.6+"
-
- ```Python hl_lines="14-22"
- {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
- ```
-
-!!! info
- 我们将`SessionLocal()`请求的创建和处理放在一个`try`块中。
-
- 然后我们在finally块中关闭它。
-
- 通过这种方式,我们确保数据库会话在请求后始终关闭,即使在处理请求时出现异常也会关闭。
-
-### 关于`request.state`
-
-`request.state`是每个`Request`对象的属性。它用于存储附加到请求本身的任意对象,例如本例中的数据库会话。您可以在[Starlette 的关于`Request`state](https://www.starlette.io/requests/#other-state)的文档中了解更多信息。
-
-对于这种情况下,它帮助我们确保在所有请求中使用单个数据库会话,然后关闭(在中间件中)。
-
-### 使用`yield`依赖项与使用中间件的区别
-
-在此处添加**中间件**与`yield`的依赖项的作用效果类似,但也有一些区别:
-
-* 中间件需要更多的代码并且更复杂一些。
-* 中间件必须是一个`async`函数。
- * 如果其中有代码必须“等待”网络,它可能会在那里“阻止”您的应用程序并稍微降低性能。
- * 尽管这里的`SQLAlchemy`工作方式可能不是很成问题。
- * 但是,如果您向等待大量I/O的中间件添加更多代码,则可能会出现问题。
-* *每个*请求都会运行一个中间件。
- * 将为每个请求创建一个连接。
- * 即使处理该请求的*路径操作*不需要数据库。
-
-!!! tip
- `tyield`当依赖项 足以满足用例时,使用`tyield`依赖项方法会更好。
-
-!!! info
- `yield`的依赖项是最近刚加入**FastAPI**中的。
-
- 所以本教程的先前版本只有带有中间件的示例,并且可能有多个应用程序使用中间件进行数据库会话管理。
+打开浏览器进入 http://127.0.0.1:8000/docs。
+
++ 您将能够与您的FastAPI应用程序交互,从真实数据库中读取数据: +
+ +
+
+
+ 如果您想独立于 FastAPI 直接浏览 SQLite 数据库(文件)以调试其内容、添加表、列、记录、修改数据等,您可以使用SQLite 的 DB Browser +
+ ++ 它看起来像这样: +
+ +
+
+
+ 您还可以使用SQLite Viewer或ExtendsClass等在线 SQLite 浏览器。 +
+ +
+ 如果你不能使用依赖项yield——例如,如果你没有使用Python 3.7并且不能安装上面提到的Python 3.6的“backports” ——你可以在类似的“中间件”中设置会话方法。
+
+ “中间件”基本功能是一个为每个请求执行的函数在请求之前进行执行相应的代码,以及在请求执行之后执行相应的代码。 +
+ +
+ 我们将添加中间件(只是一个函数)将为每个请求创建一个新的 SQLAlchemySessionLocal,将其添加到请求中,然后在请求完成后关闭它。
+
+ === "Python 3.9+" + +
{!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
+
+
+
++ === "Python 3.6+" + +
{!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
+
+
+
+
+ !!! !!! info
+ 我们将SessionLocal()请求的创建和处理放在一个try块中。
+
然后我们在finally块中关闭它。
+
+通过这种方式,我们确保数据库会话在请求后始终关闭,即使在处理请求时出现异常也会关闭。 Even if there was an exception while processing the request.
+
+
+request.state
+
+ request.state是每个Request对象的属性。 它用于存储附加到请求本身的任意对象,例如本例中的数据库会话。 您可以在Starlette 的关于Requeststate的文档中了解更多信息。
+
+ 对于这种情况下,它帮助我们确保在所有请求中使用单个数据库会话,然后关闭(在中间件中)。 +
+ +yield依赖项与使用中间件的区别
+
+ !!! info
+ yield的依赖项是最近刚加入FastAPI中的。
+
async函数。 SQLAlchemy工作方式可能不是很成问题。
+
+ !!! !!! tip
+ tyield当依赖项 足以满足用例时,使用tyield依赖项方法会更好。
+
+ !!! 在此处添加中间件与yield的依赖项的作用效果类似,但也有一些区别:
+
所以本教程的先前版本只有带有中间件的示例,并且可能有多个应用程序使用中间件进行数据库会话管理。
+
diff --git a/docs/zh/docs/tutorial/static-files.md b/docs/zh/docs/tutorial/static-files.md
index e7c5c3f0a16b0..48c361d914e67 100644
--- a/docs/zh/docs/tutorial/static-files.md
+++ b/docs/zh/docs/tutorial/static-files.md
@@ -11,24 +11,24 @@
{!../../../docs_src/static_files/tutorial001.py!}
```
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以用 `from starlette.staticfiles import StaticFiles`。
- **FastAPI** 提供了和 `starlette.staticfiles` 相同的 `fastapi.staticfiles` ,只是为了方便你,开发者。但它确实来自Starlette。
+ **FastAPI** 提供了和 `starlette.staticfiles` 相同的 `fastapi.staticfiles` ,只是为了方便你,开发者。 但它确实来自Starlette。
### 什么是"挂载"(Mounting)
"挂载" 表示在特定路径添加一个完全"独立的"应用,然后负责处理所有子路径。
-这与使用`APIRouter`不同,因为安装的应用程序是完全独立的。OpenAPI和来自你主应用的文档不会包含已挂载应用的任何东西等等。
+这与使用`APIRouter`不同,因为安装的应用程序是完全独立的。 OpenAPI和来自你主应用的文档不会包含已挂载应用的任何东西等等。
你可以在**高级用户指南**中了解更多。
## 细节
-这个 "子应用" 会被 "挂载" 到第一个 `"/static"` 指向的子路径。因此,任何以`"/static"`开头的路径都会被它处理。
+这个 "子应用" 会被 "挂载" 到第一个 `"/static"` 指向的子路径。 因此,任何以`"/static"`开头的路径都会被它处理。
- `directory="static"` 指向包含你的静态文件的目录名字。
+`directory="static"` 指向包含你的静态文件的目录名字。
`name="static"` 提供了一个能被**FastAPI**内部使用的名字。
diff --git a/docs/zh/docs/tutorial/testing.md b/docs/zh/docs/tutorial/testing.md
index 41f01f8d84a41..b1e467f73482c 100644
--- a/docs/zh/docs/tutorial/testing.md
+++ b/docs/zh/docs/tutorial/testing.md
@@ -8,10 +8,10 @@
## 使用 `TestClient`
-!!! 信息
+!!! !!! 信息
要使用 `TestClient`,先要安装 `httpx`.
- 例:`pip install httpx`.
+ E.g. 例:`pip install httpx`.
导入 `TestClient`.
@@ -27,19 +27,19 @@
{!../../../docs_src/app_testing/tutorial001.py!}
```
-!!! 提示
+!!! !!! 提示
注意测试函数是普通的 `def`,不是 `async def`。
还有client的调用也是普通的调用,不是用 `await`。
-
+
这让你可以直接使用 `pytest` 而不会遇到麻烦。
-!!! note "技术细节"
+!!! !!! note "技术细节"
你也可以用 `from starlette.testclient import TestClient`。
- **FastAPI** 提供了和 `starlette.testclient` 一样的 `fastapi.testclient`,只是为了方便开发者。但它直接来自Starlette。
+ **FastAPI** 提供了和 `starlette.testclient` 一样的 `fastapi.testclient`,只是为了方便开发者。 但它直接来自Starlette。
-!!! 提示
+!!! !!! 提示
除了发送请求之外,如果你还想测试时在FastAPI应用中调用 `async` 函数(例如异步数据库函数), 可以在高级教程中看下 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} 。
## 分离测试
@@ -54,6 +54,7 @@
```
.
+.
├── app
│ ├── __init__.py
│ └── main.py
@@ -68,10 +69,11 @@
### 测试文件
-然后你会有一个包含测试的文件 `test_main.py` 。app可以像Python包那样存在(一样是目录,但有个 `__init__.py` 文件):
+然后你会有一个包含测试的文件 `test_main.py` 。 app可以像Python包那样存在(一样是目录,但有个 `__init__.py` 文件):
``` hl_lines="5"
.
+.
├── app
│ ├── __init__.py
│ ├── main.py
@@ -96,6 +98,7 @@
```
.
+.
├── app
│ ├── __init__.py
│ ├── main.py
@@ -130,7 +133,7 @@
=== "Python 3.10+ non-Annotated"
- !!! tip
+ !!! !!! tip
Prefer to use the `Annotated` version if possible.
```Python
@@ -139,7 +142,7 @@
=== "Python 3.6+ non-Annotated"
- !!! tip
+ !!! !!! tip
Prefer to use the `Annotated` version if possible.
```Python
@@ -158,7 +161,7 @@
接着只需在测试中同样操作。
-示例:
+E.g.:
* 传一个*路径* 或*查询* 参数,添加到URL上。
* 传一个JSON体,传一个Python对象(例如一个`dict`)到参数 `json`。
@@ -168,7 +171,7 @@
关于如何传数据给后端的更多信息 (使用`httpx` 或 `TestClient`),请查阅 HTTPX 文档.
-!!! 信息
+!!! !!! 信息
注意 `TestClient` 接收可以被转化为JSON的数据,而不是Pydantic模型。
如果你在测试中有一个Pydantic模型,并且你想在测试时发送它的数据给应用,你可以使用在[JSON Compatible Encoder](encoder.md){.internal-link target=_blank}介绍的`jsonable_encoder` 。