]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🌐 Update translations for zh-hant (update-outdated) (#15896)
authorSebastián Ramírez <tiangolo@gmail.com>
Wed, 1 Jul 2026 13:59:24 +0000 (15:59 +0200)
committerGitHub <noreply@github.com>
Wed, 1 Jul 2026 13:59:24 +0000 (15:59 +0200)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yurii Motov <yurii.motov.monte@gmail.com>
60 files changed:
docs/zh-hant/docs/_llm-test.md
docs/zh-hant/docs/advanced/additional-status-codes.md
docs/zh-hant/docs/advanced/advanced-dependencies.md
docs/zh-hant/docs/advanced/dataclasses.md
docs/zh-hant/docs/advanced/events.md
docs/zh-hant/docs/advanced/generate-clients.md
docs/zh-hant/docs/advanced/json-base64-bytes.md
docs/zh-hant/docs/advanced/openapi-callbacks.md
docs/zh-hant/docs/advanced/response-change-status-code.md
docs/zh-hant/docs/advanced/response-cookies.md
docs/zh-hant/docs/advanced/response-headers.md
docs/zh-hant/docs/advanced/security/oauth2-scopes.md
docs/zh-hant/docs/advanced/settings.md
docs/zh-hant/docs/advanced/stream-data.md
docs/zh-hant/docs/advanced/wsgi.md
docs/zh-hant/docs/alternatives.md
docs/zh-hant/docs/async.md
docs/zh-hant/docs/deployment/cloud.md
docs/zh-hant/docs/deployment/concepts.md
docs/zh-hant/docs/deployment/docker.md
docs/zh-hant/docs/deployment/https.md
docs/zh-hant/docs/deployment/manually.md
docs/zh-hant/docs/editor-support.md
docs/zh-hant/docs/environment-variables.md
docs/zh-hant/docs/features.md
docs/zh-hant/docs/help-fastapi.md
docs/zh-hant/docs/how-to/configure-swagger-ui.md
docs/zh-hant/docs/how-to/custom-request-and-route.md
docs/zh-hant/docs/how-to/graphql.md
docs/zh-hant/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md
docs/zh-hant/docs/how-to/separate-openapi-schemas.md
docs/zh-hant/docs/index.md
docs/zh-hant/docs/project-generation.md
docs/zh-hant/docs/python-types.md
docs/zh-hant/docs/tutorial/bigger-applications.md
docs/zh-hant/docs/tutorial/body-nested-models.md
docs/zh-hant/docs/tutorial/body.md
docs/zh-hant/docs/tutorial/debugging.md
docs/zh-hant/docs/tutorial/dependencies/dependencies-with-yield.md
docs/zh-hant/docs/tutorial/extra-data-types.md
docs/zh-hant/docs/tutorial/extra-models.md
docs/zh-hant/docs/tutorial/first-steps.md
docs/zh-hant/docs/tutorial/handling-errors.md
docs/zh-hant/docs/tutorial/index.md
docs/zh-hant/docs/tutorial/metadata.md
docs/zh-hant/docs/tutorial/path-operation-configuration.md
docs/zh-hant/docs/tutorial/query-params-str-validations.md
docs/zh-hant/docs/tutorial/query-params.md
docs/zh-hant/docs/tutorial/request-files.md
docs/zh-hant/docs/tutorial/request-forms.md
docs/zh-hant/docs/tutorial/response-status-code.md
docs/zh-hant/docs/tutorial/schema-extra-example.md
docs/zh-hant/docs/tutorial/security/first-steps.md
docs/zh-hant/docs/tutorial/security/get-current-user.md
docs/zh-hant/docs/tutorial/security/oauth2-jwt.md
docs/zh-hant/docs/tutorial/security/simple-oauth2.md
docs/zh-hant/docs/tutorial/sql-databases.md
docs/zh-hant/docs/tutorial/static-files.md
docs/zh-hant/docs/tutorial/testing.md
docs/zh-hant/docs/virtual-environments.md

index 0ea674cd81058291e44372ec119bb92f174b6575..09efe837786c5221d86dc1d260275bce21139dc7 100644 (file)
@@ -35,7 +35,7 @@
 
 //// tab | 測試
 
-Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'".
+昨天,我的朋友寫道:「如果你正確地拼寫 incorrectly,你就把它拼成 incorrectly 了」。我回答:「正確,但 'incorrectly' 錯在它不是 '"incorrectly"'"」。
 
 /// note | 注意
 
@@ -59,7 +59,7 @@ LLM 很可能會把這段翻譯錯。重點只在於重新翻譯時是否能保
 
 `pip install "foo[bar]"`
 
-程式碼片段中字串常值的例子:"this"、'that'
+程式碼片段中字串常值的例子:`"this"`、`'that'`
 
 較難的程式碼片段中字串常值例子:`f"I like {'oranges' if orange else "apples"}"`
 
@@ -125,23 +125,23 @@ works(foo="bar")  # 這可以運作 🎉
 //// tab | 測試
 
 /// note | 注意
-Some text
+一些文字
 ///
 
 /// note | 技術細節
-Some text
+一些文字
 ///
 
 /// tip | 提示
-Some text
+一些文字
 ///
 
 /// warning | 警告
-Some text
+一些文字
 ///
 
 /// danger | 危險
-Some text
+一些文字
 ///
 
 ////
@@ -222,15 +222,15 @@ Some text
 
 ### 開發網頁應用程式 - 教學 { #develop-a-webapp-a-tutorial }
 
-Hello.
+你好。
 
 ### 型別提示與註解 { #type-hints-and-annotations }
 
-Hello again.
+再次你好。
 
 ### 超類與子類別 { #super-and-subclasses }
 
-Hello again.
+再次你好。
 
 ////
 
@@ -248,15 +248,15 @@ Hello again.
 
 //// tab | 測試
 
-* you
-* your
+* 
+* 你的
 
-* e.g.
-* etc.
+* 例如
+* 等等
 
-* `foo` as an `int`
-* `bar` as a `str`
-* `baz` as a `list`
+* `foo` 作為 `int`
+* `bar` 作為 `str`
+* `baz` 作為 `list`
 
 * 教學 - 使用者指南
 * 進階使用者指南
@@ -283,7 +283,7 @@ Hello again.
 * 即時
 * 標準
 * 預設
-* å\8cº分大小寫
+* å\8d\80分大小寫
 * 不區分大小寫
 
 * 提供應用程式服務
index 0e5941a8d6c8d2d931221a0c6fd62dd1ea9990d7..bbb4f57dc6ae182029b0889a9e64c14db6937959 100644 (file)
@@ -1,5 +1,6 @@
 # 額外的狀態碼 { #additional-status-codes }
 
+
 在預設情況下,**FastAPI** 會使用 `JSONResponse` 傳回回應,並把你從你的「路徑操作(path operation)」回傳的內容放進該 `JSONResponse` 中。
 
 它會使用預設的狀態碼,或你在路徑操作中設定的狀態碼。
index 880d92ce998bb1adc04a83f5dd549b4673be6725..92dabdaf1053d49aaf3d6b761c8a73b6721f6ac8 100644 (file)
@@ -1,5 +1,6 @@
 # 進階相依 { #advanced-dependencies }
 
+
 ## 參數化的相依 { #parameterized-dependencies }
 
 到目前為止看到的相依都是固定的函式或類別。
index 0a673889ebf5c1fa29176c7b4202d3618dce509e..64ba7dde2b76c1d1bbcc413eefaf2ee357ec4e44 100644 (file)
@@ -63,12 +63,12 @@ FastAPI 建立在 **Pydantic** 之上,我之前示範過如何使用 Pydantic
 7. 這裡 `response_model` 使用的是「`Author` dataclass 的清單」這種型別註記。
 
    同樣地,你可以把 `dataclasses` 與標準型別註記組合使用。
-8. 注意這個「路徑操作函式」使用的是一般的 `def` 而非 `async def`。
+8. 注意這個*路徑操作函式*使用的是一般的 `def` 而非 `async def`。
 
    一如往常,在 FastAPI 中你可以視需要混用 `def` 與 `async def`。
 
-   如果需要複習何時用哪個,請參考文件中關於 [`async` 與 `await`](../async.md#in-a-hurry) 的章節「In a hurry?」
-9. 這個「路徑操作函式」回傳的不是 dataclass(雖然也可以),而是一個包含內部資料的字典清單。
+   如果需要複習何時用哪個,請參考文件中關於 [`async` 與 `await`](../async.md#in-a-hurry) 的章節 _「趕時間?」_
+9. 這個*路徑操作函式*回傳的不是 dataclass(雖然也可以),而是一個包含內部資料的字典清單。
 
    FastAPI 會使用 `response_model` 參數(其中包含 dataclass)來轉換回應。
 
index 60014a90ac66741480af32965a166ba20b3ee0bf..e132d9f3ddd1668be4c680e90da5a62968804ebf 100644 (file)
@@ -1,5 +1,6 @@
 # 生命週期事件 { #lifespan-events }
 
+
 你可以定義在應用程式**啟動**之前要執行的邏輯(程式碼)。也就是說,這段程式碼會在應用開始接收請求**之前**、**只執行一次**。
 
 同樣地,你也可以定義在應用程式**關閉**時要執行的邏輯(程式碼)。在這種情況下,這段程式碼會在處理了**許多請求**之後、**只執行一次**。
index a56877ccd7edf73f9a2b9750eb7b5028b8491ea6..cc7a6865a9391d9862d6be77231797085c452d08 100644 (file)
@@ -20,20 +20,6 @@ FastAPI 會自動產生 **OpenAPI 3.1** 規格,因此你使用的任何工具
 
 ///
 
-## 來自 FastAPI 贊助商的 SDK 產生器 { #sdk-generators-from-fastapi-sponsors }
-
-本節重點介紹由贊助 FastAPI 的公司提供的**創投支持**與**公司維運**的解決方案。這些產品在高品質的自動產生 SDK 之外,還提供**額外功能**與**整合**。
-
-透過 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨,這些公司幫助確保框架與其**生態系**維持健康且**永續**。
-
-他們的贊助也展現對 FastAPI **社群**(你)的高度承諾,不僅關心提供**優良服務**,也支持 **FastAPI** 作為一個**穩健且蓬勃的框架**。🙇
-
-例如,你可以嘗試:
-
-* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
-
-其中有些方案也可能是開源或提供免費方案,讓你不需財務承諾就能試用。其他商業的 SDK 產生器也不少,你可以在網路上找到。🤓
-
 ## 建立 TypeScript SDK { #create-a-typescript-sdk }
 
 先從一個簡單的 FastAPI 應用開始:
@@ -56,7 +42,7 @@ FastAPI 會自動產生 **OpenAPI 3.1** 規格,因此你使用的任何工具
 
 ### Hey API { #hey-api }
 
-當我們有含模型的 FastAPI 應用後,就能用 Hey API 來產生 TypeScript 用戶端。最快的方法是透過 npx
+當我們有含模型的 FastAPI 應用後,就能用 Hey API 來產生 TypeScript 用戶端。最快的方法是透過 npx
 
 ```sh
 npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
@@ -194,7 +180,7 @@ npx @hey-api/openapi-ts -i ./openapi.json -o src/client
 使用自動產生的用戶端時,你會得到以下項目的**自動完成**:
 
 * 方法
-* 本文中的請求有效載荷、查詢參數等
+* Body 中的請求有效載荷、查詢參數等
 * 回應的有效載荷
 
 你也會對所有內容獲得**行內錯誤**提示。
index 9f1ecfa2ea7b222dffd8864771540202fa6a636e..bdf146b8c48b23bf16ea8d587639b105cf7fd024 100644 (file)
@@ -4,7 +4,7 @@
 
 ## Base64 與檔案 { #base64-vs-files }
 
-請先考慮是否能用 [請求檔案](../tutorial/request-files.md) 來上傳二進位資料,並用 [自訂回應 - FileResponse](./custom-response.md#fileresponse--fileresponse-) 來傳送二進位資料,而不是把它們編碼進 JSON。
+請先考慮是否能用 [請求檔案](../tutorial/request-files.md) 來上傳二進位資料,並用 [自訂回應 - FileResponse](./custom-response.md#fileresponse) 來傳送二進位資料,而不是把它們編碼進 JSON。
 
 JSON 只能包含 UTF-8 編碼的字串,因此無法直接包含原始位元組。
 
@@ -14,7 +14,7 @@ Base64 可以把二進位資料編碼成字串,但為此會使用比原始二
 
 ## Pydantic `bytes` { #pydantic-bytes }
 
-你可以宣告含有 `bytes` 欄位的 Pydantic 模型,並在模型設定中使用 `val_json_bytes`,使其在驗證輸入的 JSON 資料時使用 base64;在驗證過程中,它會將 base64 字串解碼為位元組。
+你可以宣告含有 `bytes` 欄位的 Pydantic 模型,並在模型設定中使用 `val_json_bytes`,使其在*驗證*輸入的 JSON 資料時使用 base64;在驗證過程中,它會將 base64 字串解碼為位元組。
 
 {* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
 
@@ -52,12 +52,12 @@ Base64 可以把二進位資料編碼成字串,但為此會使用比原始二
 
 ## Pydantic `bytes` 用於輸出資料 { #pydantic-bytes-for-output-data }
 
-你也可以在模型設定中搭配 `ser_json_bytes` 使用 `bytes` 欄位來處理輸出資料;當產生 JSON 回應時,Pydantic 會將位元組以 base64 進行序列化
+你也可以在模型設定中搭配 `ser_json_bytes` 使用 `bytes` 欄位來處理輸出資料;當產生 JSON 回應時,Pydantic 會將位元組以 base64 進行*序列化*
 
 {* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
 
 ## Pydantic `bytes` 用於輸入與輸出資料 { #pydantic-bytes-for-input-and-output-data }
 
-當然,你也可以使用同一個以 base64 設定的模型,同時處理輸入(以 `val_json_bytes` 驗證)與輸出(以 `ser_json_bytes` 序列化)的 JSON 資料
+當然,你也可以使用同一個以 base64 設定的模型,同時處理接收與傳送 JSON 資料時的輸入(以 `val_json_bytes` *驗證*)與輸出(以 `ser_json_bytes` *序列化*)
 
 {* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
index 8b4af6dd3dd63f747180798fbdc3a5cb1e20fbc5..6ab869accbcfdb483e516e5ceaa3ba29bcc299b1 100644 (file)
@@ -4,7 +4,7 @@
 
 當你的 API 應用呼叫「外部 API」時發生的過程稱為「回呼(callback)」。因為外部開發者撰寫的軟體會先向你的 API 發出請求,接著你的 API 再「回呼」,也就是向(可能同一位開發者建立的)外部 API 發送請求。
 
-在這種情況下,你可能想要文件化說明該外部 API 應該長什麼樣子。它應該有哪些「路徑操作」、應該接受什麼 body、應該回傳什麼 response,等等。
+在這種情況下,你可能想要文件化說明該外部 API 應該長什麼樣子。它應該有哪些「路徑操作」、應該接受什麼 body、應該回傳什麼回應,等等。
 
 ## 帶有回呼的應用 { #an-app-with-callbacks }
 
@@ -82,7 +82,7 @@ httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
 
 在撰寫回呼的文件化程式碼時,把自己想像成那位「外部開發者」會很有幫助。而且你現在是在實作「外部 API」,不是「你的 API」。
 
-暫時採用這個(外部開發者)的視角,有助於讓你更直覺地決定該把參數、body 的 Pydantic 模型、response 的模型等放在哪裡,對於那個「外部 API」會更清楚。
+暫時採用這個(外部開發者)的視角,有助於讓你更直覺地決定該把參數、body 的 Pydantic 模型、回應模型等放在哪裡,對於那個「外部 API」會更清楚。
 
 ///
 
@@ -99,7 +99,7 @@ httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
 它看起來就像一般的 FastAPI「路徑操作」:
 
 * 可能需要宣告它應該接收的 body,例如 `body: InvoiceEvent`。
-* 也可以宣告它應該回傳的 response,例如 `response_model=InvoiceEventReceived`。
+* 也可以宣告它應該回傳的回應,例如 `response_model=InvoiceEventReceived`。
 
 {* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
 
index 31b688512eecf12a50d7a52480e2e6c652f313a5..ee6373a30b63263a4d971ac919719f156b418afe 100644 (file)
@@ -1,5 +1,6 @@
 # 回應 - 變更狀態碼 { #response-change-status-code }
 
+
 你可能已經讀過,可以設定預設的[回應狀態碼](../tutorial/response-status-code.md)。
 
 但有些情況你需要回傳與預設不同的狀態碼。
index 2ba14c3f6f5cab5d6e57258318ab4e06169df007..b275523300dcd665a20ff66a6eb25d40d5b0a4fb 100644 (file)
@@ -2,9 +2,9 @@
 
 ## 使用 `Response` 參數 { #use-a-response-parameter }
 
-你可以在路徑操作函式(path operation function)中宣告一個型別為 `Response` 的參數。
+你可以在你的*路徑操作函式*(path operation function)中宣告一個型別為 `Response` 的參數。
 
-接著你可以在那個「暫時」的 `Response` 物件上設定 Cookie。
+接著你可以在那個*暫時*的 `Response` 物件上設定 Cookie。
 
 {* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}
 
@@ -12,7 +12,7 @@
 
 如果你宣告了 `response_model`,它仍會用來過濾並轉換你回傳的物件。
 
-FastAPI 會使用那個暫時的 `Response` 取出 Cookie(以及標頭與狀態碼),並將它們放入最終回應;最終回應包含你回傳的值,且會套用任何 `response_model` 的過濾。
+**FastAPI** 會使用那個*暫時*的 `Response` 取出 Cookie(以及標頭與狀態碼),並將它們放入最終回應;最終回應包含你回傳的值,且會套用任何 `response_model` 的過濾。
 
 你也可以在相依項(dependencies)中宣告 `Response` 參數,並在其中設定 Cookie(與標頭)。
 
@@ -42,9 +42,9 @@ FastAPI 會使用那個暫時的 `Response` 取出 Cookie(以及標頭與狀
 
 你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。
 
-為了方便開發者,FastAPI 也將相同的 `starlette.responses` 透過 `fastapi.responses` 提供。不過,大多數可用的回應類別都直接來自 Starlette。
+**FastAPI** 為了方便你這位開發者,也將相同的 `starlette.responses` 透過 `fastapi.responses` 提供。不過,大多數可用的回應類別都直接來自 Starlette。
 
-另外由於 `Response` 常用於設定標頭與 Cookie,FastAPI 也在 `fastapi.Response` 提供了它。
+另外由於 `Response` 常用於設定標頭與 Cookie,**FastAPI** 也在 `fastapi.Response` 提供了它。
 
 ///
 
index 4f7494a8b39f31a24c3c77137da94bc3c5a17114..002fb0e5478669bce53790e1386dddbc2f4e880f 100644 (file)
@@ -12,7 +12,7 @@
 
 如果你宣告了 `response_model`,它仍會用來過濾並轉換你回傳的物件。
 
-FastAPI 會使用那個暫時性的回應來擷取標頭(還有 Cookie 與狀態碼),並把它們放到最終回應中;最終回應包含你回傳的值,且會依任何 `response_model` 進行過濾。
+**FastAPI** 會使用那個暫時性的回應來擷取標頭(還有 Cookie 與狀態碼),並把它們放到最終回應中;最終回應包含你回傳的值,且會依任何 `response_model` 進行過濾。
 
 你也可以在依賴中宣告 `Response` 參數,並在其中設定標頭(與 Cookie)。
 
@@ -28,9 +28,9 @@ FastAPI 會使用那個暫時性的回應來擷取標頭(還有 Cookie 與狀
 
 你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。
 
-為了方便開發者,FastAPI 提供與 `starlette.responses` 相同的內容於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
+為了方便開發者,**FastAPI** 提供與 `starlette.responses` 相同的內容於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。
 
-由於 `Response` 常用來設定標頭與 Cookie,FastAPI 也在 `fastapi.Response` 提供了它。
+由於 `Response` 常用來設定標頭與 Cookie,**FastAPI** 也在 `fastapi.Response` 提供了它。
 
 ///
 
index d0a6ad0140ec34a070feaaef29d87e08ee198f29..bfd9260e3df185fab228309b53728250c587a88c 100644 (file)
@@ -1,6 +1,6 @@
 # OAuth2 範圍(scopes) { #oauth2-scopes }
 
-你可以直接在 FastAPI 中使用 OAuth2 的 scopes,已整合可無縫運作。
+你可以直接在 **FastAPI** 中使用 OAuth2 的 scopes,已整合可無縫運作。
 
 這能讓你在 OpenAPI 應用(以及 API 文件)中,依照 OAuth2 標準,實作更細粒度的權限系統。
 
@@ -8,7 +8,7 @@
 
 每次你「使用」Facebook、Google、GitHub、Microsoft、X(Twitter)「登入」時,那個應用就是在使用帶有 scopes 的 OAuth2。
 
-在本節中,你將看到如何在你的 FastAPI 應用中,用同樣的帶有 scopes 的 OAuth2 管理驗證與授權。
+在本節中,你將看到如何在你的 **FastAPI** 應用中,用同樣的帶有 scopes 的 OAuth2 管理驗證與授權。
 
 /// warning
 
@@ -42,9 +42,9 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 它們通常用來宣告特定的安全性權限,例如:
 
-- `users:read` 或 `users:write` 是常見的例子。
-- `instagram_basic` 是 Facebook / Instagram 使用的。
-- `https://www.googleapis.com/auth/drive` 是 Google 使用的。
+* `users:read` 或 `users:write` 是常見的例子。
+* `instagram_basic` 是 Facebook / Instagram 使用的。
+* `https://www.googleapis.com/auth/drive` 是 Google 使用的。
 
 /// note
 
@@ -58,9 +58,9 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 ///
 
-## å\85¨å±\80概觀 { #global-view }
+## å\85¨å\9f\9f概觀 { #global-view }
 
-先快速看看相對於主教學「使用密碼(與雜湊)、Bearer 與 JWT token 的 OAuth2」的差異([OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md))。現在加入了 OAuth2 scopes:
+先快速看看主要 **教學 - 使用者指南** 中 [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md) 範例的變更部分。現在加入了 OAuth2 scopes:
 
 {* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
 
@@ -84,7 +84,7 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 ## 內含 scopes 的 JWT token { #jwt-token-with-scopes }
 
-現在,修改 token 的路徑操作以回傳所請求的 scopes。
+現在,修改 token 的*路徑操作*以回傳所請求的 scopes。
 
 我們仍然使用相同的 `OAuth2PasswordRequestForm`。它包含屬性 `scopes`,其為 `list` 的 `str`,列出請求中收到的每個 scope。
 
@@ -100,9 +100,9 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 {* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
 
-## 在路徑操作與相依性中宣告 scopes { #declare-scopes-in-path-operations-and-dependencies }
+## 在*路徑操作*與相依性中宣告 scopes { #declare-scopes-in-path-operations-and-dependencies }
 
-現在我們宣告 `/users/me/items/` 這個路徑操作需要 `items` 這個 scope。
+現在我們宣告 `/users/me/items/` 這個*路徑操作*需要 `items` 這個 scope。
 
 為此,我們從 `fastapi` 匯入並使用 `Security`。
 
@@ -120,7 +120,7 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 你不一定需要在不同地方加上不同的 scopes。
 
-我們在這裡這樣做,是為了示範 FastAPI 如何處理在不同層級宣告的 scopes。
+我們在這裡這樣做,是為了示範 **FastAPI** 如何處理在不同層級宣告的 scopes。
 
 ///
 
@@ -130,7 +130,7 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 `Security` 其實是 `Depends` 的子類別,僅多了一個我們稍後會看到的參數。
 
-改用 `Security` 而不是 `Depends`,能讓 FastAPI 知道可以宣告安全性 scopes、在內部使用它們,並用 OpenAPI 文件化 API。
+改用 `Security` 而不是 `Depends`,能讓 **FastAPI** 知道可以宣告安全性 scopes、在內部使用它們,並用 OpenAPI 文件化 API。
 
 另外,當你從 `fastapi` 匯入 `Query`、`Path`、`Depends`、`Security` 等時,實際上它們是回傳特殊類別的函式。
 
@@ -184,7 +184,7 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 ## 驗證 `scopes` { #verify-the-scopes }
 
-我們現在要驗證,此相依性與所有相依者(包含路徑操作)所要求的所有 scopes,是否都包含在收到的 token 內所提供的 scopes 中;否則就丟出 `HTTPException`。
+我們現在要驗證,此相依性與所有相依者(包含*路徑操作*)所要求的所有 scopes,是否都包含在收到的 token 內所提供的 scopes 中;否則就丟出 `HTTPException`。
 
 為此,我們使用 `security_scopes.scopes`,其中包含一個 `list`,列出所有這些 `str` 形式的 scopes。
 
@@ -196,30 +196,30 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 由於 `get_current_active_user` 相依於 `get_current_user`,因此在 `get_current_active_user` 宣告的 `"me"` 這個 scope 會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 的必須 scopes 清單中。
 
-路徑操作本身也宣告了 `"items"` 這個 scope,因此它也會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 中。
+*路徑操作*本身也宣告了 `"items"` 這個 scope,因此它也會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 中。
 
 以下是相依性與 scopes 的階層關係:
 
-- 路徑操作 `read_own_items` 具有:
-  - 需要的 scopes `["items"]`,並有相依性:
-  - `get_current_active_user`:
-    - 相依函式 `get_current_active_user` 具有:
-      - 需要的 scopes `["me"]`,並有相依性:
-      - `get_current_user`:
-        - 相依函式 `get_current_user` 具有:
-          - 自身沒有需要的 scopes。
-          - 一個使用 `oauth2_scheme` 的相依性。
-          - 一個型別為 `SecurityScopes` 的 `security_scopes` 參數:
-            - 這個 `security_scopes` 參數有屬性 `scopes`,其為一個 `list`,包含了上面宣告的所有 scopes,因此:
-              - 對於路徑操作 `read_own_items`,`security_scopes.scopes` 會包含 `["me", "items"]`。
-              - 對於路徑操作 `read_users_me`,因為它在相依性 `get_current_active_user` 中被宣告,`security_scopes.scopes` 會包含 `["me"]`。
-              - 對於路徑操作 `read_system_status`,因為它沒有宣告任何帶 `scopes` 的 `Security`,且其相依性 `get_current_user` 也未宣告任何 `scopes`,所以 `security_scopes.scopes` 會包含 `[]`(空)。
+* *路徑操作* `read_own_items` 具有:
+    * 需要的 scopes `["items"]`,並有相依性:
+    * `get_current_active_user`:
+        * 相依函式 `get_current_active_user` 具有:
+            * 需要的 scopes `["me"]`,並有相依性:
+            * `get_current_user`:
+                * 相依函式 `get_current_user` 具有:
+                    * 自身沒有需要的 scopes。
+                    * 一個使用 `oauth2_scheme` 的相依性。
+                    * 一個型別為 `SecurityScopes` 的 `security_scopes` 參數:
+                        * 這個 `security_scopes` 參數有屬性 `scopes`,其為一個 `list`,包含了上面宣告的所有 scopes,因此:
+                            * 對於*路徑操作* `read_own_items`,`security_scopes.scopes` 會包含 `["me", "items"]`。
+                            * 對於*路徑操作* `read_users_me`,因為它在相依性 `get_current_active_user` 中被宣告,`security_scopes.scopes` 會包含 `["me"]`。
+                            * 對於*路徑操作* `read_system_status`,因為它沒有宣告任何帶 `scopes` 的 `Security`,且其相依性 `get_current_user` 也未宣告任何 `scopes`,所以 `security_scopes.scopes` 會包含 `[]`(空)。
 
 /// tip
 
-這裡重要且「神奇」的是:`get_current_user` 在每個路徑操作中,會有不同的 `scopes` 清單需要檢查。
+這裡重要且「神奇」的是:`get_current_user` 在每個*路徑操作*中,會有不同的 `scopes` 清單需要檢查。
 
-這完全取決於該路徑操作與其相依性樹中每個相依性所宣告的 `scopes`。
+這完全取決於該特定*路徑操作*與其相依性樹中每個相依性所宣告的 `scopes`。
 
 ///
 
@@ -227,11 +227,11 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 你可以在任意位置、多個地方使用 `SecurityScopes`,它不需要位於「根」相依性。
 
-它會永遠帶有對於「該特定」路徑操作與「該特定」相依性樹中,目前 `Security` 相依性所宣告的安全性 scopes(以及所有相依者):
+它會永遠帶有對於**該特定***路徑操作*與**該特定**相依性樹中,目前 `Security` 相依性所宣告的安全性 scopes(以及所有相依者)。
 
-因為 `SecurityScopes` 會擁有由相依者宣告的所有 scopes,你可以在一個集中式相依函式中用它來驗證 token 是否具有所需 scopes,然後在不同路徑操作中宣告不同的 scope 要求。
+因為 `SecurityScopes` 會擁有由相依者宣告的所有 scopes,你可以在一個集中式相依函式中用它來驗證 token 是否具有所需 scopes,然後在不同*路徑操作*中宣告不同的 scope 要求。
 
-它們會在每個路徑操作被各自獨立檢查。
+它們會在每個*路徑操作*被各自獨立檢查。
 
 ## 試用看看 { #check-it }
 
@@ -241,9 +241,9 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 如果你沒有選任何 scope,你仍會「通過驗證」,但當你嘗試存取 `/users/me/` 或 `/users/me/items/` 時,會收到沒有足夠權限的錯誤。你仍能存取 `/status/`。
 
-若你只選了 `me` 而未選 `items`,你能存取 `/users/me/`,但無法存取 `/users/me/items/`。
+若你只選了 `me` 這個 scope 而未選 `items` 這個 scope,你能存取 `/users/me/`,但無法存取 `/users/me/items/`。
 
-這就是第三方應用在取得使用者提供的 token 後,嘗試存取上述路徑操作時,會依使用者授與該應用的權限多寡而有不同結果。
+這就是第三方應用在取得使用者提供的 token 後,嘗試存取上述其中一個*路徑操作*時,會依使用者授與該應用的權限多寡而有不同結果。
 
 ## 關於第三方整合 { #about-third-party-integrations }
 
@@ -255,9 +255,9 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 但如果你要打造一個讓他人連接的 OAuth2 應用(也就是你要建立一個相當於 Facebook、Google、GitHub 等的身分驗證提供者),你應該使用其他流程之一。
 
-最常見的是 Implicit Flow(隱式流程)。
+最常見的是 implicit flow(隱式流程)。
 
-最安全的是 Authorization Code Flow(授權碼流程),但它需要更多步驟、實作也更複雜。因為較複雜,許多提供者最後會建議使用隱式流程。
+最安全的是 code flow(授權碼流程),但它需要更多步驟、實作也更複雜。因為較複雜,許多提供者最後會建議使用隱式流程。
 
 /// note
 
@@ -267,7 +267,7 @@ OAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。
 
 ///
 
-FastAPI 在 `fastapi.security.oauth2` 中提供了所有這些 OAuth2 驗證流程的工具。
+**FastAPI** 在 `fastapi.security.oauth2` 中提供了所有這些 OAuth2 驗證流程的工具。
 
 ## 在裝飾器 `dependencies` 中使用 `Security` { #security-in-decorator-dependencies }
 
index 9892f8f000be4de312d585f7a5b9b1006750ed5f..4ec1ea6726209bf003d82b4c29dae672d17e5998 100644 (file)
@@ -297,6 +297,6 @@ participant execute as Execute function
 
 你可以使用 Pydantic Settings 來處理應用程式的設定或組態,並享有 Pydantic model 的全部能力。
 
-- 透過相依可以讓測試更容易。
-- 你可以搭配 `.env` 檔使用。
-- 使用 `@lru_cache` 可以避免每個請求都重複讀取 dotenv 檔,同時仍可在測試時覆寫設定。
+* 透過相依可以讓測試更容易。
+* 你可以搭配 `.env` 檔使用。
+* 使用 `@lru_cache` 可以避免每個請求都重複讀取 dotenv 檔,同時仍可在測試時覆寫設定。
index d28cd35ec4a2c99bbcfa0a6fe677d600f07bd602..c38c48faf0feed326bdcdf4f7af9b4ab594b6cee 100644 (file)
@@ -2,7 +2,7 @@
 
 如果你要串流可用 JSON 結構化的資料,應該[串流 JSON Lines](../tutorial/stream-json-lines.md)。
 
-但如果你想串流純二進位資料或字串,以下是做法。
+但如果你想**串流純二進位資料**或字串,以下是做法。
 
 /// note
 
 
 ## 使用情境 { #use-cases }
 
-當你想串流純字串時可以用這個機制,例如直接轉發來自 AI LLM 服務的輸出。
+當你想串流純字串時可以用這個機制,例如直接轉發來自 **AI LLM** 服務的輸出。
 
-你也可以用它來串流大型二進位檔案,邊讀邊將每個區塊(chunk)串流出去,而不必一次把整個檔案載入記憶體。
+你也可以用它來串流**大型二進位檔案**,邊讀邊將每個區塊(chunk)串流出去,而不必一次把整個檔案載入記憶體。
 
-你也可以用同樣方式串流視訊或音訊,甚至可以在處理的同時即時產生並傳送。
+你也可以用同樣方式串流**視訊**或**音訊**,甚至可以在處理的同時即時產生並傳送。
 
 ## 使用 `yield` 的 `StreamingResponse` { #a-streamingresponse-with-yield }
 
@@ -40,7 +40,7 @@ FastAPI 會如實將每個資料區塊交給 `StreamingResponse`,不會嘗試
 
 {* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
 
-這也意味著使用 `StreamingResponse` 時,你擁有自由與責任,需依需求自行產生並編碼要傳送的位元組資料,與型別註解無關。 🤓
+這也意味著使用 `StreamingResponse` 時,你擁有**自由**與**責任**,需依需求自行產生並編碼要傳送的位元組資料,與型別註解無關。 🤓
 
 ### 串流位元組 { #stream-bytes }
 
index 944720bb6aaeb2a7cd16d3a44be9fc172b554dbe..161496a9829184a13fc5ebb6e08035f3628a79d3 100644 (file)
@@ -1,5 +1,6 @@
 # 包含 WSGI:Flask、Django 等 { #including-wsgi-flask-django-others }
 
+
 你可以像在 [子應用程式 - 掛載](sub-applications.md)、[在 Proxy 後方](behind-a-proxy.md) 中所見那樣掛載 WSGI 應用。
 
 為此,你可以使用 `WSGIMiddleware` 來包住你的 WSGI 應用,例如 Flask、Django 等。
index fc3f7b38e2f813dcadf1c7f6156e184bdd83d1a8..d9573892e6c2e657d2180344cf25590eb7618e84 100644 (file)
@@ -80,7 +80,7 @@ Requests 設計非常簡單直觀、容易使用,且有合理的預設值。
 
 因此,如其官網所言:
 
-> Requests is one of the most downloaded Python packages of all time
+> Requests 是有史以來下載次數最多的 Python 套件之一
 
 用法非常簡單。例如,發出一個 `GET` 請求,你會寫:
 
@@ -213,7 +213,7 @@ APISpec 由與 Marshmallow 相同的開發者創建。
 
 它是個很棒但被低估的工具。它理應比許多 Flask 外掛更受歡迎,可能因為它的文件過於簡潔與抽象。
 
-這解決了在 Python 文件字串中撰寫 YAML(另一種語法)的问题
+這解決了在 Python 文件字串中撰寫 YAML(另一種語法)的問題
 
 在打造 **FastAPI** 前,我最喜歡的後端技術組合就是 Flask、Flask-apispec、Marshmallow 與 Webargs。
 
index 74eb8081da6a3bfae4e11328ebf00f7557de6726..cad99a5a60737d0fd1249c46d0c3493c58306176 100644 (file)
@@ -2,7 +2,7 @@
 
 有關*路徑操作函式*的 `async def` 語法的細節與非同步 (asynchronous) 程式碼、並行 (concurrency) 與平行 (parallelism) 的一些背景知識。
 
-## 趕時間嗎? { #in-a-hurry }
+## 趕時間嗎 { #in-a-hurry }
 
 <abbr title="too long; didn't read - 太長不看"><strong>TL;DR:</strong></abbr>
 
@@ -14,7 +14,6 @@ results = await some_library()
 
 然後,使用 `async def` 宣告你的*路徑操作函式*:
 
-
 ```Python hl_lines="2"
 @app.get('/')
 async def read_results():
@@ -49,7 +48,7 @@ def results():
 
 ---
 
-**注意**:你可以在*路徑操作函式*中混合使用 `def` 和 `async def` ,並使用最適合你需求的方式來定義每個函式。FastAPI 會幫你做正確的處理。
+**注意**:你可以在*路徑操作函式*中混合使用 `def` 和 `async def`,並使用最適合你需求的方式來定義每個函式。FastAPI 會幫你做正確的處理。
 
 無論如何,在上述哪種情況下,FastAPI 仍將以非同步方式運行,並且速度非常快。
 
@@ -57,7 +56,7 @@ def results():
 
 ## 技術細節 { #technical-details }
 
-現代版本的 Python 支援使用 **「協程」** 的 **`async` 和 `await`** 語法來寫 **「非同步程式碼」**。
+現代版本的 Python 支援使用稱為 **「協程」** 的東西,透過 **`async` 和 `await`** 語法來寫 **「非同步程式碼」**。
 
 接下來我們逐一介紹:
 
@@ -67,39 +66,40 @@ def results():
 
 ## 非同步程式碼 { #asynchronous-code }
 
-非同步程式碼僅意味著程式語言 💬 有辦法告訴電腦/程式 🤖 在程式碼中的某個點,它 🤖 需要等待某些事情完成。讓我們假設這些事情被稱為「慢速檔案」📝。
+非同步程式碼僅意味著程式語言 💬 有辦法告訴電腦 / 程式 🤖 在程式碼中的某個點,它 🤖 需要等待其他地方的*某些事情*完成。讓我們假設這個*某些事情*被稱為「慢速檔案」📝。
+
+因此,在「慢速檔案」📝 完成的這段時間,電腦可以去處理一些其他工作。
 
-因此,在等待「慢速檔案」📝 完成的這段時間,電腦可以去處理一些其他工作。
+接著電腦 / 程式 🤖 會在每次有機會時回來,因為它又在等待,或是在它 🤖 完成當時手上的所有工作時回來。然後它 🤖 會查看是否有任何等待中的任務已經完成,並執行必要的後續操作。
 
-接著程式 🤖 會在有空檔時回來查看是否有等待的工作已經完成,並執行必要的後續操作。
+接下來,它 🤖 取得第一個完成的任務(例如我們的「慢速檔案」📝),並繼續執行與之相關的所有操作。
 
-接下來,它 🤖 完成第一個工作(例如我們的「慢速檔案」📝)並繼續執行相關的所有操作。
-這個「等待其他事情」通常指的是一些相對較慢的(與處理器和 RAM 記憶體的速度相比)的 <abbr title="Input and Output - 輸入與輸出">I/O</abbr> 操作,比如說:
+這個「等待其他事情」通常指的是一些相對較慢的(與處理器和 RAM 記憶體的速度相比)的 <abbr title="Input and Output - 輸入與輸出">I/O</abbr> 操作,比如說等待:
 
 * 透過網路傳送來自用戶端的資料
-* 從網路接收來自用戶端的資料
-* 從磁碟讀取檔案內容
-* 將內容寫入磁碟
+* 你的程式傳送的資料透過網路被用戶端接收
+* 系統從磁碟讀取檔案內容並提供給你的程式
+* 你的程式交給系統的內容被寫入磁碟
 * 遠端 API 操作
-* 資料庫操作
-* 資料庫查詢
+* 資料庫操作完成
+* 資料庫查詢回傳結果
 * 等等
 
-由於大部分的執行時間都消耗在等待 <abbr title="Input and Output - 輸入與輸出">I/O</abbr> 操作上,因此這些操作被稱為 "I/O 密集型" 操作。
+由於大部分的執行時間都消耗在等待 <abbr title="Input and Output - 輸入與輸出">I/O</abbr> 操作上,因此這些操作被稱為 "I/O bound" 操作。
 
-之所以稱為「非同步」,是因為電腦/程式不需要與那些耗時的任務「同步」,等待任務完成的精確時間,然後才能取得結果並繼續工作。
+之所以稱為「非同步」,是因為電腦 / 程式不需要與那些耗時的任務「同步」,在什麼都不做的情況下等待任務完成的精確時間,才能取得任務結果並繼續工作。
 
-相反地,非同步系統在任務完成後,可以讓任務稍微等一下(幾微秒),等待電腦/程式完成手頭上的其他工作,然後再回來取得結果繼續進行。
+相反地,作為一個「非同步」系統,任務完成後,可以讓任務稍微排隊等一下(幾微秒),等待電腦 / 程式完成手頭上的其他工作,然後再回來取得結果繼續進行。
 
-相對於「非同步」(asynchronous),「同步」(synchronous)也常被稱作「順序性」(sequential),因為電腦/程式會依序執行所有步驟,即便這些步驟涉及等待,才會切換到其他任務。
+相對於「非同步」(asynchronous),「同步」(synchronous)也常被稱作「順序性」(sequential),因為電腦 / 程式會依序執行所有步驟,即便這些步驟涉及等待,才會切換到其他任務。
 
 ### 並行與漢堡 { #concurrency-and-burgers }
 
-上述非同步程式碼的概念有時也被稱為「並行」,它不同於「平行」
+上述**非同步**程式碼的概念有時也被稱為**「並行」**,它不同於**「平行」**
 
-並行和平行都與 "不同的事情或多或少同時發生" 有關。
+**並行**和平行都與 "不同的事情或多或少同時發生" 有關。
 
-但並行和平行之間的細節是完全不同的。
+但*並行*和平行之間的細節是完全不同的。
 
 為了理解差異,請想像以下有關漢堡的故事:
 
@@ -113,7 +113,7 @@ def results():
 
 <img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
 
-收銀員通知廚房準備你的漢堡(儘管他們還在為前面其他顧客準備食物)。
+收銀員通知廚房的廚師,讓他們知道需要準備你的漢堡(儘管他們還在為前面其他顧客準備食物)。
 
 <img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
 
@@ -125,7 +125,7 @@ def results():
 
 在等待漢堡的同時,你可以與戀人選一張桌子,然後坐下來聊很長一段時間(因為漢堡十分豪華,準備特別費工。)
 
-這段時間,你還能欣賞你的戀人有多麼的可愛、聰明與迷人。✨😍✨
+當你和戀人坐在桌邊等待漢堡時,你可以把這段時間拿來欣賞你的戀人有多麼棒、可愛又聰明 ✨😍✨。
 
 <img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
 
@@ -135,7 +135,7 @@ def results():
 
 <img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
 
-你和戀人享用這頓大餐,整個過程十分開心✨
+你和戀人享用這頓大餐,整個過程十分開心
 
 <img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
 
@@ -147,21 +147,21 @@ def results():
 
 ---
 
-想像你是故事中的電腦程式 🤖。
+想像你是故事中的電腦 / 程式 🤖。
 
 當你排隊時,你在放空😴,等待輪到你,沒有做任何「生產性」的事情。但這沒關係,因為收銀員只是接單(而不是準備食物),所以排隊速度很快。
 
-然後,當輪到你時,你開始做真正「有生產力」的工作,處理菜單,決定你想要什麼,替戀人選擇餐點,付款,確認你給了正確的帳單或信用卡,檢查你是否被正確收費,確認訂單中的項目是否正確等等。
+然後,當輪到你時,你開始做真正「有生產力」的工作,處理菜單,決定你想要什麼,取得戀人的選擇,付款,確認你給了正確的帳單或信用卡,檢查你是否被正確收費,確認訂單中的項目是否正確等等。
 
 但是,即使你還沒有拿到漢堡,你與收銀員的工作已經「暫停」了 ⏸,因為你必須等待 🕙 漢堡準備好。
 
 但當你離開櫃檯,坐到桌子旁,拿著屬於你的號碼等待時,你可以把注意力 🔀 轉移到戀人身上,並開始「工作」⏯ 🤓——也就是和戀人調情 😍。這時你又開始做一些非常「有生產力」的事情。
 
-接著,收銀員 💁 將你的號碼顯示在櫃檯螢幕上,並告訴你「漢堡已經做好了」。但你不會瘋狂地立刻跳起來,因為顯示的號碼變成了你的。你知道沒有人會搶走你的漢堡,因為你有自己的號碼,他們也有他們的號碼。
+接著,收銀員 💁 透過把你的號碼顯示在櫃檯螢幕上,表示「漢堡已經做好了」,但你不會在顯示的號碼變成你的號碼時就瘋狂地立刻跳起來。你知道沒有人會搶走你的漢堡,因為你有自己的號碼,他們也有他們的號碼。
 
-所以你會等戀人講完故事(完成當前的工作 ⏯/正在進行的任務 🤓),然後微笑著溫柔地說你要去拿漢堡了 ⏸。
+所以你會等戀人講完故事(完成當前的工作 ⏯ / 正在進行的任務 🤓),然後微笑著溫柔地說你要去拿漢堡了 ⏸。
 
-然後你走向櫃檯 🔀,回到已經完成的最初任務 ⏯,拿起漢堡,說聲謝謝,並帶回桌上。這就結束了與櫃檯的互動步驟/任務 ⏹,接下來會產生一個新的任務,「吃漢堡」 🔀 ⏯,而先前的「拿漢堡」任務已經完成了 ⏹。
+然後你走向櫃檯 🔀,回到已經完成的最初任務 ⏯,拿起漢堡,說聲謝謝,並帶回桌上。這就結束了與櫃檯互動的步驟 / 任務 ⏹。接著,這又產生了一個新的任務,「吃漢堡」🔀 ⏯,而先前的「拿漢堡」任務已經完成了 ⏹。
 
 ### 平行漢堡 { #parallel-burgers }
 
@@ -181,19 +181,19 @@ def results():
 
 <img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
 
-收銀員走進廚房準備食物
+收銀員走進廚房。
 
 你站在櫃檯前等待 🕙,以免其他人先拿走你的漢堡,因為這裡沒有號碼牌系統。
 
 <img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
 
\94±æ\96¼ä½ å\92\8cæ\88\80人é\83½å¿\99è\91\97ä¸\8dè®\93å\88¥äººæ\90¶èµ°ä½ ç\9a\84漢堡ï¼\8cç­\89漢堡æº\96å\82\99好æ\99\82,你根本無法專心和戀人互動。😞
\94±æ\96¼ä½ å\92\8cæ\88\80人é\83½å¿\99è\91\97ä¸\8dè®\93å\88¥äººæ\8f\92å\88°ä½ å\89\8dé\9d¢ä¸¦å\9c¨æ¼¢å ¡é\80\81ä¾\86æ\99\82æ\8b¿èµ°ä½ ç\9a\84漢堡,你根本無法專心和戀人互動。😞
 
-這是「同步」(synchronous)工作,你和收銀員/廚師 👨‍🍳 是「同步化」的。你必須等到 🕙 收銀員/廚師 👨‍🍳 完成漢堡並交給你的那一刻,否則別人可能會拿走你的餐點。
+這是「同步」(synchronous)工作,你和收銀員 / 廚師 👨‍🍳 是「同步化」的。你必須等到 🕙 收銀員 / 廚師 👨‍🍳 完成漢堡並交給你的那一刻,否則別人可能會拿走你的餐點。
 
 <img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
 
-最終,經過長時間的等待 🕙,收銀員/廚師 👨‍🍳 拿著漢堡回來了。
+最終,經過長時間在櫃檯前的等待 🕙,收銀員 / 廚師 👨‍🍳 拿著漢堡回來了。
 
 <img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
 
@@ -203,7 +203,7 @@ def results():
 
 <img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
 
-整個過程中沒有太多談情說愛,因為大部分時間 🕙 都花在櫃檯前等待。😞
+整個過程中沒有太多聊天或談情說愛,因為大部分時間 🕙 都花在櫃檯前等待。😞
 
 /// note | 注意
 
@@ -213,15 +213,15 @@ def results():
 
 ---
 
-在這個平行漢堡的情境下,你是一個程式 🤖 且有兩個處理器(你和戀人),兩者都在等待 🕙 並專注於等待櫃檯上的餐點 🕙,等待的時間非常長。
+在這個平行漢堡的情境下,你是一個程式 🤖 且有兩個處理器(你和戀人),兩者都在等待 🕙 並專注 ⏯ 於在櫃檯前等待 🕙,等待的時間非常長。
 
-這家速食店有 8 個處理器(收銀員/廚師)。而並行漢堡店可能只有 2 個處理器(一位收銀員和一位廚師)。
+這家速食店有 8 個處理器(收銀員 / 廚師)。而並行漢堡店可能只有 2 個處理器(一位收銀員和一位廚師)。
 
 儘管如此,最終的體驗並不是最理想的。😞
 
 ---
 
-這是與漢堡類似的故事。🍔
+這是與漢堡類似的平行版本故事。🍔
 
 一個更「現實」的例子,想像一間銀行。
 
@@ -241,29 +241,29 @@ def results():
 
 許多用戶正在使用你的應用程式,而你的伺服器則在等待 🕙 這些用戶不那麼穩定的網路來傳送請求。
 
-接著,再次等待 🕙 回應。
+接著,再次等待 🕙 回應回來
 
-這種「等待」 🕙 通常以微秒來衡量,但累加起來,最終還是花費了很多等待時間。
+這種「等待」🕙 通常以微秒來衡量,但累加起來,最終還是花費了很多等待時間。
 
-這就是為什麼對於 Web API 來說,使用非同步程式碼 ⏸🔀⏯ 是非常有意的。
+這就是為什麼對於 Web API 來說,使用非同步程式碼 ⏸🔀⏯ 是非常有意的。
 
 這種類型的非同步性正是 NodeJS 成功的原因(儘管 NodeJS 不是平行的),這也是 Go 語言作為程式語言的一個強大優勢。
 
\80\99è\88\87 **FastAPI** æ\89\80è\83½æ\8f\90ä¾\9bç\9a\84æ\80§è\83½æ°´å¹³相同。
\80\99è\88\87 **FastAPI** æ\89\80è\83½æ\8f\90ä¾\9bç\9a\84æ\95\88è\83½æ°´æº\96相同。
 
-你可以同時利用並行性和平行性,進一步提升效能,這比大多數已測試的 NodeJS 框架都更快,並且與 Go 語言相當,而 Go 是一種更接近 C 的編譯語言([感謝 Starlette](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1))。
+你可以同時利用平行性和非同步性,進一步提升效能,這比大多數已測試的 NodeJS 框架都更快,並且與 Go 語言相當,而 Go 是一種更接近 C 的編譯語言([這都要歸功於 Starlette](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1))。
 
-### 並行比平行更好嗎 { #is-concurrency-better-than-parallelism }
+### 並行比平行更好嗎 { #is-concurrency-better-than-parallelism }
 
 不是的!這不是故事的本意。
 
 並行與平行不同。並行在某些 **特定** 的需要大量等待的情境下表現更好。正因如此,並行在 Web 應用程式開發中通常比平行更有優勢。但並不是所有情境都如此。
 
-因此,為了平衡報導,想像下面這個短故事
+因此,為了平衡報導,想像下面這個短故事
 
 > 你需要打掃一間又大又髒的房子。
 
-*是的,這就是全部的故事。*
+*是的,這就是全部的故事*。
 
 ---
 
@@ -273,32 +273,32 @@ def results():
 
 無論輪流執行與否(並行),你都需要相同的工時完成任務,同時需要執行相同工作量。
 
-但是,在這種情境下,如果你可以邀請8位前收銀員/廚師(現在是清潔工)來幫忙,每個人(加上你)負責房子的某個區域,這樣你就可以 **平行** 地更快完成工作。
+但是,在這種情境下,如果你可以邀請 8 位前收銀員 / 廚師(現在是清潔工)來幫忙,每個人(加上你)負責房子的某個區域,這樣你就可以在額外協助下 **平行** 地更快完成工作。
 
 在這個場景中,每個清潔工(包括你)都是一個處理器,完成工作的一部分。
 
-由於大多數的執行時間都花在實際的工作上(而不是等待),而電腦中的工作由 <abbr title="Central Processing Unit - 中央處理器">CPU</abbr> 完成,因此這些問題被稱為「CPU 密集型」。
+由於大多數的執行時間都花在實際的工作上(而不是等待),而電腦中的工作由 <abbr title="Central Processing Unit - 中央處理器">CPU</abbr> 完成,因此這些問題被稱為「CPU bound」。
 
 ---
 
-常見的 CPU 密集型操作範例包括那些需要進行複雜數學計算的任務。
+常見的 CPU bound 操作範例包括那些需要進行複雜數學計算的任務。
 
 例如:
 
-* **音訊**或**圖像處理**
-* **電腦視覺**:一張圖片由數百萬個像素組成,每個像素有 3 個值/顏色,處理這些像素通常需要同時進行大量計算;
-* **機器學習**: 通常需要大量的「矩陣」和「向量」運算。想像一個包含數字的巨大電子表格,並所有的數字同時相乘;
-* **深度學習**: 這是機器學習的子領域,同樣適用。只不過這不僅僅是一張數字表格,而是大量的數據集合,並且在很多情況下,你會使用特殊的處理器來構建或使用這些模型。
+* **音訊**或**圖像處理**
+* **電腦視覺**:一張圖片由數百萬個像素組成,每個像素有 3 個值 / 顏色,處理這些像素通常需要同時進行大量計算。
+* **機器學習**:通常需要大量的「矩陣」和「向量」運算。想像一個包含數字的巨大電子表格,並將所有數字同時相乘。
+* **深度學習**:這是機器學習的子領域,同樣適用。只不過這不僅僅是一張要相乘的數字表格,而是大量的數據集合,並且在很多情況下,你會使用特殊的處理器來構建及 / 或使用這些模型。
 
 ### 並行 + 平行: Web + 機器學習 { #concurrency-parallelism-web-machine-learning }
 
 使用 **FastAPI**,你可以利用並行的優勢,這在 Web 開發中非常常見(這也是 NodeJS 的最大吸引力)。
 
-但你也可以利用平行與多行程 (multiprocessing)(讓多個行程同時運行) 的優勢來處理機器學習系統中的 **CPU 密集型**工作。
+但你也可以利用平行與多行程 (multiprocessing)(讓多個行程同時運行) 的優勢來處理機器學習系統中的 **CPU bound** 工作。
 
-這一點,再加上 Python 是 **資料科學**、機器學習,尤其是深度學習的主要語言,讓 **FastAPI** 成為資料科學/機器學習 Web API 和應用程式(以及許多其他應用程式)的絕佳選擇。
+這一點,再加上 Python 是 **資料科學**、機器學習,尤其是深度學習的主要語言,讓 **FastAPI** 成為資料科學 / 機器學習 Web API 和應用程式(以及許多其他應用程式)的絕佳選擇。
 
-想了解如何在生產環境中實現這種平行性,請參見 [部](deployment/index.md)。
+想了解如何在生產環境中實現這種平行性,請參見 [部](deployment/index.md)。
 
 ## `async` 和 `await` { #async-and-await }
 
@@ -310,37 +310,37 @@ def results():
 burgers = await get_burgers(2)
 ```
 
-這裡的關鍵是 `await`。它告訴 Python 必須等待 ⏸ `get_burgers(2)` 完成它的工作 🕙, 然後將結果儲存在 `burgers` 中。如此,Python 就可以在此期間去處理其他事情 🔀 ⏯ (例如接收另一個請求)。
+這裡的關鍵是 `await`。它告訴 Python 必須等待 ⏸ `get_burgers(2)` 完成它的工作 🕙,然後將結果儲存在 `burgers` 中。如此,Python 就可以在此期間去處理其他事情 🔀 ⏯(例如接收另一個請求)。
 
-è¦\81è®\93 `await` é\81\8bä½\9cï¼\8cå®\83å¿\85é \88ä½\8dæ\96¼æ\94¯æ\8c\81非同步功能的函式內。為此,只需使用 `async def` 宣告函式:
+è¦\81è®\93 `await` é\81\8bä½\9cï¼\8cå®\83å¿\85é \88ä½\8dæ\96¼æ\94¯æ\8f´非同步功能的函式內。為此,只需使用 `async def` 宣告函式:
 
 ```Python hl_lines="1"
 async def get_burgers(number: int):
-    # Do some asynchronous stuff to create the burgers
+    # 做一些非同步的事情來製作漢堡
     return burgers
 ```
 
-...而不是 `def`:
+...而不是 `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
 ```
 
-使用 `async def`,Python 知道在該函式內需要注意 `await`,並且它可以「暫停」 ⏸ 執行該函式,然後執行其他任務 🔀 後回來。
+使用 `async def`,Python 知道在該函式內需要注意 `await` 運算式,並且它可以「暫停」⏸ 執行該函式,然後執行其他任務 🔀 後回來。
 
 當你想要呼叫 `async def` 函式時,必須使用「await」。因此,這樣寫將無法運行:
 
 ```Python
-# This won't work, because get_burgers was defined with: async def
+# 這不會運作,因為 get_burgers 是用 async def 定義的
 burgers = get_burgers(2)
 ```
 
 ---
 
-å¦\82æ\9e\9cä½ æ­£å\9c¨ä½¿ç\94¨æ\9f\90å\80\8bå\87½å¼\8f庫ï¼\8cå®\83å\91\8a訴你å\8f¯ä»¥ä½¿ç\94¨ `await` å\91¼å\8f«å®\83ï¼\8cé\82£éº¼ä½ é\9c\80è¦\81ç\94¨ `async def` å®\9a義*路徑操作函式*,如:
+å¦\82æ\9e\9cä½ æ­£å\9c¨ä½¿ç\94¨æ\9f\90å\80\8bå\87½å¼\8f庫ï¼\8cå®\83å\91\8a訴你å\8f¯ä»¥ä½¿ç\94¨ `await` å\91¼å\8f«å®\83ï¼\8cé\82£éº¼ä½ é\9c\80è¦\81ç\94¨ `async def` å»ºç«\8b使ç\94¨å®\83ç\9a\84*路徑操作函式*,如:
 
 ```Python hl_lines="2-3"
 @app.get('/burgers')
@@ -357,7 +357,7 @@ async def read_burgers():
 
 那麼,這就像「先有雞還是先有蛋」的問題,要如何呼叫第一個 `async` 函式呢?
 
-如果你使用 FastAPI,無需擔心這個問題,因為「第一個」函式將是你的*路徑操作函式*,FastAPI 會知道如何正確處理這個問題。
+如果你使用 **FastAPI**,無需擔心這個問題,因為「第一個」函式將是你的*路徑操作函式*,FastAPI 會知道如何正確處理這個問題。
 
 但如果你想在沒有 FastAPI 的情況下使用 `async` / `await`,你也可以這樣做。
 
@@ -367,9 +367,9 @@ Starlette(和 **FastAPI**)是基於 [AnyIO](https://anyio.readthedocs.io/en/
 
 特別是,你可以直接使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 來處理更複雜的並行使用案例,這些案例需要你在自己的程式碼中使用更高階的模式。
 
-即使你不使用 **FastAPI**,你也可以使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 來撰寫自己的非同步應用程式,並獲得高相容性及一些好處(例如「結構化並行」)。
+即使你不使用 FastAPI,你也可以使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 來撰寫自己的非同步應用程式,並獲得高相容性及一些好處(例如*結構化並行*)。
 
-我另外在 AnyIO 之上做了一個薄封裝的函式庫,稍微改進型別註解以獲得更好的**自動補全**、**即時錯誤**等。同時它也提供友善的介紹與教學,幫助你**理解**並撰寫**自己的非同步程式碼**:[Asyncer](https://asyncer.tiangolo.com/)。當你需要**將非同步程式碼與一般**(阻塞/同步)**程式碼整合**時,它特別實用。
+我另外在 AnyIO 之上做了一個薄封裝的函式庫,稍微改進型別註解以獲得更好的**自動補全**、**即時錯誤**等。同時它也提供友善的介紹與教學,幫助你**理解**並撰寫**自己的非同步程式碼**:[Asyncer](https://asyncer.tiangolo.com/)。當你需要**將非同步程式碼與一般**(阻塞 / 同步)**程式碼整合**時,它特別實用。
 
 ### 其他形式的非同步程式碼 { #other-forms-of-asynchronous-code }
 
@@ -381,21 +381,21 @@ Starlette(和 **FastAPI**)是基於 [AnyIO](https://anyio.readthedocs.io/en/
 
 但在此之前,處理非同步程式碼要更加複雜和困難。
 
-在較舊的 Python 版本中,你可能會使用多執行緒或 [Gevent](https://www.gevent.org/)。但這些程式碼要更難以理解、調試和思考。
+在較舊的 Python 版本中,你可能會使用多執行緒或 [Gevent](https://www.gevent.org/)。但這些程式碼要更難以理解、偵錯和思考。
 
-在較舊的 NodeJS / 瀏覽器 JavaScript 中,你會使用「回呼」,這可能會導致“回呼地獄”
+在較舊的 NodeJS / 瀏覽器 JavaScript 中,你會使用「回呼」。這可能會導致「回呼地獄」
 
 ## 協程 { #coroutines }
 
-「協程」只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西,可以啟動它,並且在某個時刻它會結束,但它也可能在內部暫停 ⏸,只要遇到 `await`。
+**協程**只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西,可以啟動它,並且在某個時刻它會結束,但它也可能在內部暫停 ⏸,只要遇到 `await`。
 
-這種使用 `async` 和 `await` 的非同步程式碼功能通常被概括為「協程」。這與 Go 語言的主要特性「Goroutines」相似。
+但這種使用 `async` 和 `await` 的非同步程式碼功能,通常被概括為使用「協程」。這與 Go 語言的主要特性「Goroutines」相似。
 
 ## 結論 { #conclusion }
 
 讓我們再次回顧之前的句子:
 
-> ç\8f¾ä»£ç\89\88æ\9c¬ç\9a\84 Python æ\94¯æ\8c\81使ç\94¨ **"å\8d\94ç¨\8b"** ç\9a\84 **`async` å\92\8c `await`** èª\9eæ³\95ä¾\86寫 **"é\9d\9eå\90\8cæ­¥ç¨\8bå¼\8f碼"**。
+> ç\8f¾ä»£ç\89\88æ\9c¬ç\9a\84 Python æ\94¯æ\8f´ä½¿ç\94¨ç¨±ç\82º **ã\80\8cå\8d\94ç¨\8bã\80\8d** ç\9a\84æ\9d±è¥¿ï¼\8cé\80\8fé\81\8e **`async` å\92\8c `await`** èª\9eæ³\95ä¾\86寫 **ã\80\8cé\9d\9eå\90\8cæ­¥ç¨\8bå¼\8f碼ã\80\8d**。
 
 現在應該能明白其含意了。✨
 
@@ -407,7 +407,7 @@ Starlette(和 **FastAPI**)是基於 [AnyIO](https://anyio.readthedocs.io/en/
 
 你大概可以跳過這段。
 
-這裡是有關 FastAPI 內部技術細節。
+這裡是有關 **FastAPI** 底層如何運作的非常技術性的細節。
 
 如果你有相當多的技術背景(例如協程、執行緒、阻塞等),並且對 FastAPI 如何處理 `async def` 與常規 `def` 感到好奇,請繼續閱讀。
 
@@ -415,9 +415,9 @@ Starlette(和 **FastAPI**)是基於 [AnyIO](https://anyio.readthedocs.io/en/
 
 ### 路徑操作函式 { #path-operation-functions }
 
-當你使用 `def` 而不是 `async def` 宣告*路徑操作函式*時,該函式會在外部的執行緒池(threadpool)中執行,然後等待結果,而不是直接呼叫(因為這樣會阻塞伺服器)。
+當你使用一般的 `def` 而不是 `async def` 宣告*路徑操作函式*時,該函式會在外部的執行緒池(threadpool)中執行,然後等待結果,而不是直接呼叫(因為這樣會阻塞伺服器)。
 
-å¦\82æ\9e\9cä½ ä¾\86è\87ªæ\96¼å\85¶ä»\96ä¸\8d以é\80\99種æ\96¹å¼\8fé\81\8bä½\9cç\9a\84é\9d\9eå\90\8cæ­¥æ¡\86æ\9e¶ï¼\8cè\80\8cä¸\94ä½ ç¿\92æ\85£æ\96¼ä½¿ç\94¨æ\99®é\80\9aç\9a\84 `def` å®\9a義å\83\85é\80²è¡\8cç°¡å\96®è¨\88ç®\97ç\9a\84*è·¯å¾\91æ\93\8dä½\9cå\87½å¼\8f*ï¼\8cç\9b®ç\9a\84æ\98¯ç\8d²å¾\97å¾®å°\8fç\9a\84æ\80§è\83½å¢\9eç\9b\8aï¼\88大ç´\84 100 å¥\88ç§\92ï¼\89ï¼\8cè«\8b注æ\84\8fï¼\8cå\9c¨ FastAPI ä¸­ï¼\8cæ\95\88æ\9e\9cæ\9c\83å®\8cå\85¨ç\9b¸å\8f\8dã\80\82å\9c¨é\80\99äº\9bæ\83\85æ³\81ä¸\8bï¼\8cæ\9c\80好使ç\94¨ `async def`ï¼\8cé\99¤é\9d\9eä½ ç\9a\84*è·¯å¾\91æ\93\8dä½\9cå\87½å¼\8f\9f·è¡\8cé\98»å¡\9eç\9a\84 <abbr title="Input/Output - è¼¸å\85¥/輸å\87º: ç£\81ç¢\9fè®\80寫æ\88\96網路通訊。">I/O</abbr> 的程式碼。
+å¦\82æ\9e\9cä½ ä¾\86è\87ªæ\96¼å\85¶ä»\96ä¸\8d以é\80\99種æ\96¹å¼\8fé\81\8bä½\9cç\9a\84é\9d\9eå\90\8cæ­¥æ¡\86æ\9e¶ï¼\8cè\80\8cä¸\94ä½ ç¿\92æ\85£æ\96¼ä½¿ç\94¨æ\99®é\80\9aç\9a\84 `def` å®\9a義å\83\85é\80²è¡\8cç°¡å\96®è¨\88ç®\97ç\9a\84*è·¯å¾\91æ\93\8dä½\9cå\87½å¼\8f*ï¼\8cç\9b®ç\9a\84æ\98¯ç\8d²å¾\97å¾®å°\8fç\9a\84æ\95\88è\83½å¢\9eç\9b\8aï¼\88大ç´\84 100 å¥\88ç§\92ï¼\89ï¼\8cè«\8b注æ\84\8fï¼\8cå\9c¨ **FastAPI** ä¸­ï¼\8cæ\95\88æ\9e\9cæ\9c\83å®\8cå\85¨ç\9b¸å\8f\8dã\80\82å\9c¨é\80\99äº\9bæ\83\85æ³\81ä¸\8bï¼\8cæ\9c\80好使ç\94¨ `async def`ï¼\8cé\99¤é\9d\9eä½ ç\9a\84*è·¯å¾\91æ\93\8dä½\9cå\87½å¼\8f\9f·è¡\8cé\98»å¡\9eç\9a\84 <abbr title="Input/Output - è¼¸å\85¥/輸å\87º: ç£\81ç¢\9fè®\80å\8f\96æ\88\96寫å\85¥ã\80\81網路通訊。">I/O</abbr> 的程式碼。
 
 不過,在這兩種情況下,**FastAPI** [仍然很快](index.md#performance),至少與你之前的框架相當(或者更快)。
 
@@ -427,18 +427,18 @@ Starlette(和 **FastAPI**)是基於 [AnyIO](https://anyio.readthedocs.io/en/
 
 ### 子依賴項 { #sub-dependencies }
 
-你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md)(作為函式定義的參數),其中一些可能是用 `async def` 宣告,也可能是用 `def` 宣告。它們仍然可以正常運作,用 `def` 定義的那些將會在外部的執行緒中呼叫(來自執行緒池),而不是被「等待」。
+你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md)(作為函式定義的參數),其中一些可能是用 `async def` 宣告,也可能是用一般的 `def` 宣告。它們仍然可以正常運作,用一般的 `def` 定義的那些將會在外部的執行緒中呼叫(來自執行緒池),而不是被「等待」。
 
 ### 其他輔助函式 { #other-utility-functions }
 
-你可以直接呼叫任何使用 `def` 或 `async def` 建立的其他輔助函式,FastAPI 不會影響你呼叫它們的方式。
+你可以直接呼叫任何使用一般的 `def` 或 `async def` 建立的其他輔助函式,FastAPI 不會影響你呼叫它們的方式。
 
-這與 FastAPI 為你呼叫*路徑操作函式*和依賴項的邏輯有所不同
+這與 FastAPI 為你呼叫的函式有所不同:*路徑操作函式*和依賴項
 
-如果你的輔助函式是用 `def` 宣告的,它將會被直接呼叫(按照你在程式碼中撰寫的方式),而不是在執行緒池中。如果該函式是用 `async def` 宣告,那麼你在呼叫時應該使用 `await` 等待其結果。
+如果你的輔助函式是用 `def` 宣告的一般函式,它將會被直接呼叫(按照你在程式碼中撰寫的方式),而不是在執行緒池中。如果該函式是用 `async def` 宣告,那麼你在程式碼中呼叫它時應該使用 `await` 等待其結果。
 
 ---
 
 再一次強調,這些都是非常技術性的細節,如果你特地在尋找這些資訊,這些內容可能會對你有幫助。
 
\90¦å\89\87ï¼\8cå\8fªé\9c\80é\81µå¾ªä¸\8aé\9d¢æ\8f\90å\88°ç\9a\84æ\8c\87å¼\95å\8d³å\8f¯ï¼\9a<a href="#in-a-hurry">è¶\95æ\99\82é\96\93å\97\8e?</a>。
\90¦å\89\87ï¼\8cå\8fªé\9c\80é\81µå¾ªä¸\8aé\9d¢æ\8f\90å\88°ç« ç¯\80ç\9a\84æ\8c\87å¼\95å\8d³å\8f¯ï¼\9a<a href="#in-a-hurry">è¶\95æ\99\82é\96\93å\97\8eï¼\9f</a>。
index 86d216ca6f43dec256aa27ee67f6ac46cf6e2f12..caf05ec1629bc4d3bd813912e022ab1d63294c7b 100644 (file)
@@ -16,7 +16,7 @@ FastAPI Cloud 是 *FastAPI and friends* 開源專案的主要贊助與資金提
 
 ## 雲端供應商 - 贊助商 { #cloud-providers-sponsors }
 
-其他一些雲端供應商也會 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨。🙇
+其他一些雲端供應商也會 ✨ [**贊助 FastAPI**](https://github.com/sponsors/tiangolo) ✨。🙇
 
 你也可以參考他們的指南並試用其服務:
 
index 0b8677bfd339b8509deed87b6eb93ba1d7333519..070bcf5448569d347254256d002019f34f6aaffd 100644 (file)
@@ -1,5 +1,6 @@
 # 部署概念 { #deployments-concepts }
 
+
 當你要部署一個 FastAPI 應用,或其實任何類型的 Web API 時,有幾個你可能在意的概念。掌握這些概念後,你就能找出最適合部署你應用的方式。
 
 一些重要的概念包括:
index 650873887c54544fb47f7f8b75ddb460695ea006..b10299def8d30945c5c9fb983f4be1def0f00843 100644 (file)
@@ -258,7 +258,7 @@ CMD fastapi run app/main.py --port 80
 
 你可以在 [Docker 關於 shell 與 exec 形式的文件](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form) 閱讀更多。
 
-使用 `docker compose` 時這會特別明顯。技術細節請見這段 Docker Compose 常見問題:[為什麼我的服務要花 10 秒才重新建立或停止?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop)
+使用 `docker compose` 時這會特別明顯。技術細節請見這段 Docker Compose 常見問題:[為什麼我的服務要花 10 秒才重新建立或停止?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop)
 
 #### 目錄結構 { #directory-structure }
 
@@ -454,7 +454,7 @@ Traefik 與 Docker、Kubernetes 等整合良好,因此為你的容器設定與
 
 ## 複本 - 行程數量 { #replication-number-of-processes }
 
-如果你在有 Kubernetes、Docker Swarm Mode、Nomad,或其他類似的分散式容器管理系統的「<dfn title="一組配置為連接並共同運作的機器">叢集</dfn>」上運作,那你大概會希望在「叢集層級」處理「複本」,而不是在每個容器內使用「行程管理器」(例如帶有 workers 的 Uvicorn)。
+如果你在有 Kubernetes、Docker Swarm Mode、Nomad,或其他類似的分散式容器管理系統的「<dfn title="一組被設定為以某種方式連接並共同運作的機器。">叢集</dfn>」上運作,那你大概會希望在「叢集層級」處理「複本」,而不是在每個容器內使用「行程管理器」(例如帶有 workers 的 Uvicorn)。
 
 像 Kubernetes 這類的分散式容器管理系統,通常內建處理「容器複本」以及支援進入請求的「負載平衡」的能力——全部都在「叢集層級」。
 
@@ -574,7 +574,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
 
 你大概「不應該」使用這個基底 Docker 映像(或其他類似的)。
 
-如果你使用 Kubernetes(或其他)並已在叢集層級設定「複本」、使用多個「容器」。在這些情況下,更好的做法是如上所述[從零建置映像](#build-a-docker-image-for-fastapi)。
+如果你使用 Kubernetes(或其他)並已在叢集層級設定「複本」、使用多個「容器」。在這些情況下,更好的做法是如上所述「從零建置映像」:[為 FastAPI 建置 Docker 映像](#build-a-docker-image-for-fastapi)。
 
 若你需要多個 workers,只要使用 `--workers` 命令列選項即可。
 
index ddafcb34b108f0768338765d2cdcee5e98bb4851..fead5a4b9bda903ba23b70fcb75c316347fe063e 100644 (file)
@@ -1,5 +1,6 @@
 # 關於 HTTPS { #about-https }
 
+
 人們很容易以為 HTTPS 只是「啟用或未啟用」的功能。
 
 但實際上複雜得多。
index 2260f69425bad8353377f8b6caa77a8d96d360b0..590d0b011cad45afcc4d5d12fef35ba97a69fa28 100644 (file)
@@ -40,7 +40,7 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
 
 這在多數情況下都適用。😎
 
-你可以用這個指令在容器、伺服器等環境中啟動你的 FastAPI 應用。
+你可以用這個指令在容器、伺服器等環境中啟動你的 **FastAPI** 應用。
 
 ## ASGI 伺服器 { #asgi-servers }
 
@@ -48,7 +48,7 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
 
 FastAPI 採用建立 Python 網頁框架與伺服器的標準 <abbr title="Asynchronous Server Gateway Interface - 非同步伺服器閘道介面">ASGI</abbr>。FastAPI 是一個 ASGI 網頁框架。
 
-在遠端伺服器機器上執行 FastAPI 應用(或任何 ASGI 應用)所需的關鍵是 ASGI 伺服器程式,例如 Uvicorn;`fastapi` 指令預設就是使用它。
+在遠端伺服器機器上執行 **FastAPI** 應用(或任何 ASGI 應用)所需的關鍵是 ASGI 伺服器程式,例如 **Uvicorn**;`fastapi` 指令預設就是使用它。
 
 有數個替代方案,包括:
 
@@ -61,11 +61,11 @@ FastAPI 採用建立 Python 網頁框架與伺服器的標準 <abbr title="Async
 
 有個命名上的小細節請留意。💡
 
-「server(伺服器)」一詞常同時用來指遠端/雲端電腦(實體或虛擬機器),也用來指在該機器上執行的程式(例如 Uvicorn)。
+「**server**(伺服器)」一詞常同時用來指遠端/雲端電腦(實體或虛擬機器),也用來指在該機器上執行的程式(例如 Uvicorn)。
 
 因此看到「server」時,文意可能指這兩者之一。
 
-指涉遠端機器時,常稱為 server、machine、VM(虛擬機器)、node 等,這些都指某種遠端機器(通常執行 Linux),你會在其上執行程式。
+指涉遠端機器時,常稱為 **server**、**machine**、**VM**(虛擬機器)、**node** 等,這些都指某種遠端機器(通常執行 Linux),你會在其上執行程式。
 
 ## 安裝伺服器程式 { #install-the-server-program }
 
@@ -136,13 +136,13 @@ Uvicorn 與其他伺服器支援 `--reload` 選項,對開發期間很有幫助
 
 `--reload` 會消耗更多資源,也較不穩定等。
 
-它在開發階段很實用,但在生產環境中不應使用。
+它在 **開發** 階段很實用,但在 **生產環境** 中**不應**使用。
 
 ///
 
 ## 部署觀念 { #deployment-concepts }
 
-上述範例會啟動伺服器程式(如 Uvicorn),以單一行程在指定連接埠(如 `80`)上監聽所有 IP(`0.0.0.0`)。
+上述範例會啟動伺服器程式(如 Uvicorn),以**單一行程**在指定連接埠(如 `80`)上監聽所有 IP(`0.0.0.0`)。
 
 這是基本概念。但你很可能還需要處理一些額外事項,例如:
 
index ff4d8f43db6c81d419f1c96b41ab51b68d4184c5..a48336d9b928f64bc5f77d1e2531ca2999debb2d 100644 (file)
@@ -1,5 +1,6 @@
 # 編輯器支援 { #editor-support }
 
+
 官方的 [FastAPI 擴充套件](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) 透過支援路徑操作(path operation)探索、導覽,以及 FastAPI Cloud 部署與即時日誌串流,強化你的 FastAPI 開發流程。
 
 想了解更多關於此擴充套件的細節,請參考其 [GitHub 儲存庫](https://github.com/fastapi/fastapi-vscode) 中的 README。
index 09264b7e26693e898f69903ab199c61910d500db..71248ac638a4a57577b439465e60ec4d983062a7 100644 (file)
@@ -1,5 +1,6 @@
 # 環境變數 { #environment-variables }
 
+
 /// tip
 
 如果你已經知道什麼是「環境變數」並且知道如何使用它們,你可以放心跳過這一部分。
index 82d4871c10ae85ac01db2580a4676b9ac71d5f15..193e4a1d6ec962efe804a0333852b15517504e38 100644 (file)
@@ -6,14 +6,14 @@
 
 ### 建立在開放標準的基礎上 { #based-on-open-standards }
 
-* 使用 [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) 來建立 API,包含 <dfn title="也稱為:端點、路由">路徑</dfn><dfn title="也稱為 HTTP 方法,例如 POST、GET、PUT、DELETE">操作</dfn>、參數、請求內文、安全性等宣告。
+* 使用 [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) 來建立 API,包含 <dfn title="也稱為:端點、路由">路徑</dfn> <dfn title="也稱為 HTTP 方法,例如 POST、GET、PUT、DELETE">操作</dfn>、參數、請求內文、安全性等宣告。
 * 使用 [**JSON Schema**](https://json-schema.org/)(因為 OpenAPI 本身就是基於 JSON Schema)自動生成資料模型文件。
 * 經過縝密的研究後圍繞這些標準進行設計,而不是事後在已有系統上附加的一層功能。
 * 這也讓我們在多種語言中可以使用自動**用戶端程式碼生成**。
 
 ### 能夠自動生成文件 { #automatic-docs }
 
-FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由於該框架基於 OpenAPI,因此有多種選擇,預設提供了兩種。
+互動式 API 文件與探索用的 Web 使用者介面。由於該框架基於 OpenAPI,因此有多種選擇,預設包含 2 種。
 
 * [**Swagger UI**](https://github.com/swagger-api/swagger-ui) 提供互動式探索,讓你可以直接從瀏覽器呼叫並測試你的 API 。
 
@@ -27,22 +27,22 @@ FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由
 
 這一切都基於標準的 **Python 型別**宣告(感謝 Pydantic)。無需學習新的語法,只需使用標準的現代 Python。
 
-如果你需要 2 分鐘來習如何使用 Python 型別(即使你不使用 FastAPI),可以看看這個簡短的教學:[Python 型別](python-types.md)。
+如果你需要 2 分鐘來習如何使用 Python 型別(即使你不使用 FastAPI),可以看看這個簡短的教學:[Python 型別](python-types.md)。
 
-如果你寫帶有 Python 型別的程式碼
+你撰寫帶有型別的標準 Python
 
 ```Python
 from datetime import date
 
 from pydantic import BaseModel
 
-# å®£å\91\8aä¸\80å\80\8bè®\8aæ\95¸ç\82º string
-# 並在函式中獲得 editor support
+# å°\87è®\8aæ\95¸å®£å\91\8aç\82º str
+# 並在函式內取得 editor support
 def main(user_id: str):
     return user_id
 
 
-# 宣告一個 Pydantic model
+# 一個 Pydantic model
 class User(BaseModel):
     id: int
     name: str
@@ -65,9 +65,9 @@ my_second_user: User = User(**second_user_data)
 
 /// note
 
-`**second_user_data` 意思是:
+`**second_user_data` 意思是
 
-將 `second_user_data` 字典直接作為 key-value 引數傳遞,等同於:`User(id=4, name="Mary", joined="2018-11-30")`
+將 `second_user_data` dict 的 keys 和 values 直接作為 key-value 引數傳遞,等同於:`User(id=4, name="Mary", joined="2018-11-30")`
 
 ///
 
@@ -75,31 +75,31 @@ my_second_user: User = User(**second_user_data)
 
 整個框架的設計是為了讓使用變得簡單且直觀,在開始開發之前,所有決策都在多個編輯器上進行了測試,以確保提供最佳的開發體驗。
 
-在最近的 Python 開發者調查中,我們能看到[被使用最多的功能是 autocompletion](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)。
+在 Python 開發者調查中,我們能清楚看到[最常用的功能之一是「autocompletion」](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)。
 
 整個 **FastAPI** 框架就是基於這一點,任何地方都可以進行自動補齊。
 
-ä½ å¹¾ä¹\8eä¸\8dé\9c\80è¦\81ç¶\93常ä¾\86å\9b\9e看文件。
+ä½ å¾\88å°\91é\9c\80è¦\81å\9b\9eä¾\86æ\9f¥看文件。
 
 在這裡,你的編輯器可能會這樣幫助你:
 
-* 在 [Visual Studio Code](https://code.visualstudio.com/) 中:
+* 在 [Visual Studio Code](https://code.visualstudio.com/) 中
 
 ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
 
-* 在 [PyCharm](https://www.jetbrains.com/pycharm/) 中:
+* 在 [PyCharm](https://www.jetbrains.com/pycharm/) 中
 
 ![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)
 
-你將能進行程式碼補齊,這是在之前你可能曾認為不可能的事。例如,請求 JSON body(可能是巢狀的)中的鍵 `price`。
+你將能進行程式碼補齊,這是在之前你可能曾認為不可能的事。例如,來自請求的 JSON body(可能是巢狀的)中的鍵 `price`。
 
 這樣比較不會輸錯鍵名,不用來回翻看文件,也不用來回滾動尋找你最後使用的 `username` 或者 `user_name`。
 
 ### 簡潔 { #short }
 
-FastAPI 為你提供了**預設值**,讓你不必在初期進行繁瑣的配置,一切都可以自動運作。如果你有更具體的需求,則可以進行調整和自定義
+它為所有內容提供合理的**預設值**,並且每處都可選擇性設定。所有參數都可以微調,以完成你需要的行為並定義你需要的 API
 
-但預設情況下,一切都「直接可用」
+但預設情況下,一切都 **「直接可用」**
 
 ### 驗證 { #validation }
 
@@ -109,47 +109,47 @@ FastAPI 為你提供了**預設值**,讓你不必在初期進行繁瑣的配
     * 字串 (`str`) 欄位,定義最小或最大長度。
     * 數字 (`int`, `float`) 與其最大值和最小值等。
 
-* 驗證外來的型別,比如:
-    * URL
-    * Email
-    * UUID
+* 驗證較特殊的型別,比如:
+    * URL
+    * Email
+    * UUID
     * ...等等。
 
 所有的驗證都由完善且強大的 **Pydantic** 處理。
 
 ### 安全性及身份驗證 { #security-and-authentication }
 
-FastAPI 已經整合了安全性和身份驗證的功能,但不會強制與特定的資料庫或資料模型進行綁定
+FastAPI 已經整合了安全性和身份驗證的功能。不需在資料庫或資料模型上妥協
 
-OpenAPI 中定義的安全模式,包括:
+OpenAPI 中定義的所有安全模式,包括:
 
 * HTTP 基本認證。
 * **OAuth2**(也使用 **JWT tokens**)。在 [OAuth2 with JWT](tutorial/security/oauth2-jwt.md) 查看教學。
 * API 密鑰,在:
-    * 標頭(Header)
-    * 查詢參數
+    * 標頭
+    * 查詢參數
     * Cookies,等等。
 
-加上來自 Starlette(包括 **session cookie**)的所有安全特性。
+加上來自 Starlette(包括 **session cookies**)的所有安全特性。
 
\89\80æ\9c\89ç\9a\84é\80\99äº\9bé\83½æ\98¯å\8f¯é\87\8dè¤\87使ç\94¨ç\9a\84å·¥å\85·å\92\8cå¥\97ä»¶ï¼\8cå\8f¯ä»¥è¼\95é¬\86è\88\87ä½ ç\9a\84系統ã\80\81è³\87æ\96\99å\84²å­\98ï¼\88Data Storesï¼\89ã\80\81é\97\9cè\81¯å¼\8fè³\87æ\96\99庫ï¼\88RDBMSï¼\89以å\8f\8aé\9d\9eé\97\9cè\81¯å¼\8fè³\87æ\96\99庫ï¼\88NoSQLï¼\89ç­\89等整合。
\89\80æ\9c\89ç\9a\84é\80\99äº\9bé\83½æ\98¯å\8f¯é\87\8dè¤\87使ç\94¨ç\9a\84å·¥å\85·å\92\8cå\85\83ä»¶ï¼\8cå\8f¯ä»¥è¼\95é¬\86è\88\87ä½ ç\9a\84系統ã\80\81è³\87æ\96\99å\84²å­\98ã\80\81é\97\9cè\81¯å¼\8få\92\8c NoSQL è³\87æ\96\99庫等整合。
 
 ### 依賴注入(Dependency Injection) { #dependency-injection }
 
 FastAPI 有一個使用簡單,但是非常強大的 <dfn title='也稱為「components」、「resources」、「services」、「providers」'><strong>依賴注入</strong></dfn> 系統。
 
-* 依賴項甚至可以有自己的依賴,從而形成一個層級或**依賴圖**的結構。
+* 依賴項甚至可以有自己的依賴,從而形成一個層級或**依賴項的「圖」**結構。
 * 所有**自動化處理**都由框架完成。
-* 依賴項不僅能從請求中提取資料,還能**對 API 的路徑操作進行強化**,並自動生成文檔
-* 即使是依賴項中定義的*路徑操作參數*,也會**自動進行驗證**。
-* æ\94¯æ\8c\81è¤\87é\9b\9cç\9a\84ç\94¨æ\88身份驗證系統、**資料庫連接**等。
-* 不與資料庫、前端等進行強制綁定,但能輕鬆整合它們。
+* 所有依賴項都可以從請求中要求資料,並**擴充路徑操作**的限制條件與自動文件
+* 即使是依賴項中定義的*路徑操作*參數,也會**自動進行驗證**。
+* æ\94¯æ\8f´è¤\87é\9b\9cç\9a\84使ç\94¨è\80\85身份驗證系統、**資料庫連接**等。
+* **不需妥協**資料庫、前端等。但能輕鬆整合它們。
 
 ### 無限制「擴充功能」 { #unlimited-plug-ins }
 
-或者說,無需其他額外配置,直接導入並使用你所需要的程式碼
+或者說,其實不需要它們,匯入並使用你需要的程式碼即可
 
-任何整合都被設計得非常簡單易用(通過依賴注入),你只需用與*路徑操作*相同的結構和語法,用兩行程式碼就能為你的應用程式建立一個「擴充功能」。
+任何整合都被設計得非常簡單易用(通過依賴),你只需用與*路徑操作*相同的結構和語法,用 2 行程式碼就能為你的應用程式建立一個「plug-in」。
 
 ### 測試 { #tested }
 
@@ -159,7 +159,9 @@ FastAPI 有一個使用簡單,但是非常強大的 <dfn title='也稱為「co
 
 ## Starlette 特性 { #starlette-features }
 
-**FastAPI** 完全相容且基於 [**Starlette**](https://www.starlette.dev/)。所以,你有其他的 Starlette 程式碼也能正常運作。`FastAPI` 實際上是 `Starlette` 的一個子類別。所以,如果你已經知道或者使用過 Starlette,大部分的功能會以相同的方式運作。
+**FastAPI** 完全相容且基於 [**Starlette**](https://www.starlette.dev/)。所以,你有其他的 Starlette 程式碼也能正常運作。
+
+`FastAPI` 實際上是 `Starlette` 的一個子類別。所以,如果你已經知道或者使用過 Starlette,大部分的功能會以相同的方式運作。
 
 通過 **FastAPI** 你可以獲得所有 **Starlette** 的特性(FastAPI 就像加強版的 Starlette):
 
@@ -169,31 +171,31 @@ FastAPI 有一個使用簡單,但是非常強大的 <dfn title='也稱為「co
 * 支援啟動和關閉事件。
 * 有基於 HTTPX 的測試用戶端。
 * 支援 **CORS**、GZip、靜態檔案、串流回應。
-* 支援 **Session 和 Cookie** 
+* 支援 **Session 和 Cookie**。
 * 100% 測試覆蓋率。
-* 100% 型別註的程式碼庫。
+* 100% 型別註的程式碼庫。
 
 ## Pydantic 特性 { #pydantic-features }
 
-**FastAPI** 完全相容且基於 [**Pydantic**](https://docs.pydantic.dev/)。所以,你有其他 Pydantic 程式碼也能正常作。
+**FastAPI** 完全相容且基於 [**Pydantic**](https://docs.pydantic.dev/)。所以,你有其他 Pydantic 程式碼也能正常作。
 
\9b¸å®¹å\8c\85æ\8b¬å\9fºæ\96¼ Pydantic ç\9a\84å¤\96é\83¨å\87½å¼\8f庫ï¼\8cä¾\8bå¦\82ç\94¨æ\96¼è³\87æ\96\99庫ç\9a\84 <abbr title="Object-Relational Mapper - ç\89©ä»¶é\97\9cè\81¯å°\8dæ\98 å\99¨">ORM</abbr>sã\80\81<abbr title="Object-Document Mapper - 物件文件對映器">ODM</abbr>s。
\9b¸å®¹å\8c\85æ\8b¬å\90\8c樣å\9fºæ\96¼ Pydantic ç\9a\84å¤\96é\83¨å\87½å¼\8f庫ï¼\8cä¾\8bå¦\82ç\94¨æ\96¼è³\87æ\96\99庫ç\9a\84 <abbr title="Object-Relational Mapper - ç\89©ä»¶é\97\9cè\81¯å°\8dæ\98 å\99¨">ORM</abbr>s å\92\8c <abbr title="Object-Document Mapper - 物件文件對映器">ODM</abbr>s。
 
-這也意味著在很多情況下,你可以把從請求中獲得的物件**直接傳到資料庫**,因為所有資料都會自動進行驗證。
\80\99ä¹\9fæ\84\8få\91³è\91\97å\9c¨å¾\88å¤\9aæ\83\85æ³\81ä¸\8bï¼\8cä½ å\8f¯ä»¥æ\8a\8aå¾\9eè«\8bæ±\82中ç\8d²å¾\97ç\9a\84ç\9b¸å\90\8cç\89©ä»¶**ç\9b´æ\8e¥å\82³å\88°è³\87æ\96\99庫**ï¼\8cå\9b ç\82ºæ\89\80æ\9c\89è³\87æ\96\99é\83½æ\9c\83è\87ªå\8b\95é\80²è¡\8cé©\97è­\89ã\80\82
 
 反之亦然,在很多情況下,你也可以把從資料庫中獲取的物件**直接傳給客戶端**。
 
 通過 **FastAPI** 你可以獲得所有 **Pydantic** 的特性(FastAPI 基於 Pydantic 做了所有的資料處理):
 
-* **更簡單**:
-    * 不需要學習新的 micro-language 來定義結構
+* **不傷腦筋**:
+    * 不需要學習新的 schema 定義 micro-language
     * 如果你知道 Python 型別,你就知道如何使用 Pydantic。
-* 和你的 **<abbr title="Integrated Development Environment - 整合開發環境類似於程式碼編輯器">IDE</abbr>/<dfn title="檢查程式碼錯誤的程式">linter</dfn>/brain** 都能好好配合:
-    * 因為 Pydantic 的資料結構其實就是你自己定義的類別實例,所以自動補齊、linting、mypy 以及你的直覺都能很好地在經過驗證的資料上發揮作用。
+* 和你的 **<abbr title="Integrated Development Environment - 整合開發環境類似於程式碼編輯器">IDE</abbr>/<dfn title="檢查程式碼錯誤的程式">linter</dfn>/brain** 都能好好配合:
+    * 因為 pydantic 的資料結構其實就是你自己定義的類別實例,所以自動補齊、linting、mypy 以及你的直覺都能很好地在經過驗證的資料上發揮作用。
 * 驗證**複雜結構**:
-    * 使用 Pydantic 模型時,你可以把資料結構分層設計,並且用 Python 的 `List` 和 `Dict` 等型別來定義
+    * 使用階層式 Pydantic 模型、Python `typing` 的 `List` 和 `Dict` 等
     * 驗證器讓我們可以輕鬆地定義和檢查複雜的資料結構,並把它們轉換成 JSON Schema 進行記錄。
-    * 你可以擁有深層**巢狀的 JSON** 物件,並對它們進行驗證和註
-* **å\8f¯æ\93´å±\95**:
-    * Pydantic è®\93æ\88\91å\80\91å\8f¯ä»¥å®\9a義客製å\8c\96ç\9a\84è³\87æ\96\99å\9e\8bå\88¥ï¼\8cæ\88\96è\80\85ä½ å\8f¯ä»¥ä½¿ç\94¨å¸¶æ\9c\89 validator è£\9d飾å\99¨ç\9a\84æ\96¹æ³\95ä¾\86æ\93´å±\95模型中的驗證功能。
+    * 你可以擁有深層**巢狀的 JSON** 物件,並對它們進行驗證和註
+* **å\8f¯æ\93´å\85\85**:
+    * Pydantic è®\93æ\88\91å\80\91å\8f¯ä»¥å®\9a義客製å\8c\96ç\9a\84è³\87æ\96\99å\9e\8bå\88¥ï¼\8cæ\88\96è\80\85ä½ å\8f¯ä»¥ä½¿ç\94¨å¸¶æ\9c\89 validator è£\9d飾å\99¨ç\9a\84æ\96¹æ³\95ä¾\86æ\93´å\85\85模型中的驗證功能。
 * 100% 測試覆蓋率。
index 69af48a56f48c0c383a7d5687db0d380edf5828d..4a4a4fda593af29692de3b961acaf3903f9528e4 100644 (file)
@@ -1,5 +1,6 @@
 # 協助 { #help }
 
+
 你想要協助 FastAPI,或取得關於 FastAPI 的協助嗎?
 
 有一些非常簡單的方式可以提供協助並取得協助。
index cbb63ef5e6ced27c1f790967a63eeca835f481b0..37d9487b40824a8e2b07f495af37ee62af0c0709 100644 (file)
@@ -65,6 +65,6 @@ presets: [
 ]
 ```
 
-這些是 JavaScript 物件,而不是字串,因此無法直接從 Python 程式碼傳遞。
+這些是 **JavaScript** 物件,而不是字串,因此無法直接從 Python 程式碼傳遞。
 
-若需要使用這類僅限 JavaScript 的設定,你可以使用上面介紹的方法:覆寫所有 Swagger UI 的路徑操作(path operation),並手動撰寫所需的 JavaScript。
+若需要使用這類僅限 JavaScript 的設定,你可以使用上述其中一種方法。覆寫整個 Swagger UI *路徑操作*,並手動撰寫所需的 JavaScript。
index 00031fcaad53c4a55338b909ef60795b83064a56..afd097f51c013287b79b0ff5006f2eb2a9c78a82 100644 (file)
 
 {* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}
 
-在此範例中,`router` 底下的路徑操作會使用自訂的 `TimedRoute` 類別,並在回應中多加上一個 `X-Response-Time` 標頭,標示產生該回應所花費的時間:
+在此範例中,`router` 底下的 *路徑操作* 會使用自訂的 `TimedRoute` 類別,並在回應中多加上一個 `X-Response-Time` 標頭,標示產生該回應所花費的時間:
 
 {* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}
index 24e4d89792eecfc574ca3f2971985eddf31b4944..fce5f4119015012b0be3026bd7c39e5636d2554f 100644 (file)
@@ -1,22 +1,22 @@
 # GraphQL { #graphql }
 
-由於 FastAPI 基於 ASGI 標準,整合任何與 ASGI 相容的 GraphQL 函式庫都很容易。
+由於 **FastAPI** 基於 **ASGI** 標準,整合任何也相容於 ASGI 的 **GraphQL** 函式庫都很容易。
 
-你可以在同一個應用程式中同時使用一般的 FastAPI 路徑操作 (path operation) 與 GraphQL。
+你可以在同一個應用程式中同時使用一般的 FastAPI *路徑操作 (path operation)* 與 GraphQL。
 
 /// tip
 
-GraphQL 解決某些非常特定的使用情境。
+**GraphQL** 解決某些非常特定的使用情境。
 
-與一般的 Web API 相比,它有優點也有缺點
+與一般的 **Web API** 相比,它有**優點**也有**缺點**
 
-請確認在你的使用情境中,這些效益是否足以彌補其限制。 🤓
+請確認在你的使用情境中,這些**效益**是否足以彌補其**限制**。 🤓
 
 ///
 
 ## GraphQL 函式庫 { #graphql-libraries }
 
-下面是支援 ASGI 的部分 GraphQL 函式庫,你可以與 FastAPI 一起使用:
+下面是支援 **ASGI** 的部分 **GraphQL** 函式庫,你可以與 **FastAPI** 一起使用:
 
 * [Strawberry](https://strawberry.rocks/) 🍓
     * 提供 [FastAPI 文件](https://strawberry.rocks/docs/integrations/fastapi)
@@ -29,9 +29,9 @@ GraphQL 解決某些非常特定的使用情境。
 
 ## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }
 
-如果你需要或想使用 GraphQL,[Strawberry](https://strawberry.rocks/) 是推薦的函式庫,因為它的設計與 FastAPI 最接近,全部都基於型別註解 (type annotations)
+如果你需要或想使用 **GraphQL**,[**Strawberry**](https://strawberry.rocks/) 是**推薦的**函式庫,因為它的設計最接近 **FastAPI** 的設計,全部都基於**型別註解**
 
-視你的使用情境而定,你可能會偏好其他函式庫,但如果你問我,我大概會建議你先試試 Strawberry
+視你的使用情境而定,你可能會偏好其他函式庫,但如果你問我,我大概會建議你先試試 **Strawberry**
 
 以下是如何將 Strawberry 與 FastAPI 整合的一個小例子:
 
@@ -45,7 +45,7 @@ GraphQL 解決某些非常特定的使用情境。
 
 早期版本的 Starlette 提供 `GraphQLApp` 類別以整合 [Graphene](https://graphene-python.org/)。
 
-它已在 Starlette 中被棄用,但如果你的程式碼使用了它,可以輕鬆遷移到 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3),涵蓋相同的使用情境,且介面幾乎相同
+它已在 Starlette 中被棄用,但如果你的程式碼使用了它,可以輕鬆**遷移**到 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3),涵蓋相同的使用情境,且介面**幾乎相同**
 
 /// tip
 
@@ -55,6 +55,6 @@ GraphQL 解決某些非常特定的使用情境。
 
 ## 進一步了解 { #learn-more }
 
-你可以在 [官方 GraphQL 文件](https://graphql.org/) 中進一步了解 GraphQL
+你可以在 [官方 GraphQL 文件](https://graphql.org/) 中進一步了解 **GraphQL**
 
 你也可以透過上述連結閱讀各個函式庫的更多內容。
index 4495e3dd70ae3508af843636d6d866c0f8e6106d..77a58251e2045983963970140e6e73f862d6b040 100644 (file)
@@ -8,6 +8,8 @@ FastAPI 0.119.0 透過 Pydantic v2 內的 `pydantic.v1` 提供對 Pydantic v1 
 
 FastAPI 0.126.0 移除了對 Pydantic v1 的支援,但在一段時間內仍支援 `pydantic.v1`。
 
+FastAPI 0.128.0 也移除了對 `pydantic.v1` 的支援,因此最新版本的 FastAPI 需要 Pydantic v2。
+
 /// warning
 
 Pydantic 團隊自 **Python 3.14** 起,已停止在最新的 Python 版本中支援 Pydantic v1。
@@ -46,7 +48,7 @@ Pydantic 提供從 v1 遷移到 v2 的官方[遷移指南](https://docs.pydantic
 
 ## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }
 
-Pydantic v2 å\85§å\90«å­\90模çµ\84 `pydantic.v1`ï¼\8cæ\8f\90ä¾\9b Pydantic v1 ç\9a\84æ\89\80æ\9c\89å\85§å®¹ã\80\82ä½\86å\9c¨ Python 3.13 ä»¥ä¸\8a版本不再支援。
+Pydantic v2 å\85§å\90«å­\90模çµ\84 `pydantic.v1`ï¼\8cæ\8f\90ä¾\9b Pydantic v1 ç\9a\84æ\89\80æ\9c\89å\85§å®¹ã\80\82ä½\86å\9c¨ Python 3.13 ä¹\8bå¾\8cç\9a\84版本不再支援。
 
 這表示你可以安裝最新的 Pydantic v2,並從該子模組匯入並使用舊的 Pydantic v1 元件,就像安裝了舊版 Pydantic v1 一樣。
 
@@ -54,6 +56,16 @@ Pydantic v2 內含子模組 `pydantic.v1`,提供 Pydantic v1 的所有內容
 
 ### FastAPI 對 v2 中 Pydantic v1 的支援 { #fastapi-support-for-pydantic-v1-in-v2 }
 
+/// warning
+
+FastAPI 對 `pydantic.v1` 模型的支援是在 **FastAPI 0.119.0** 加入,並在 **FastAPI 0.128.0** 移除。這原本是為了遷移到 Pydantic v2 而提供的臨時協助。
+
+在目前版本的 FastAPI 中,在你的應用使用 `pydantic.v1` 模型會引發錯誤。
+
+本節其餘內容描述的是只在那些較舊版本中可用的臨時支援。
+
+///
+
 自 FastAPI 0.119.0 起,也支援透過 Pydantic v2 內的 Pydantic v1(部分)以協助遷移至 v2。
 
 因此,你可以先升級到最新的 Pydantic v2,並將匯入改為使用 `pydantic.v1` 子模組,在多數情況下即可正常運作。
@@ -122,6 +134,12 @@ graph TB
 
 ### 分步遷移 { #migrate-in-steps }
 
+/// warning
+
+以下描述的,在同一應用中同時使用 Pydantic v1 與 v2 模型進行漸進式遷移,只適用於 **FastAPI 0.119.0 到 0.127.x**。這項支援已在 **FastAPI 0.128.0** 移除,最新版本需要 **Pydantic v2** 模型。
+
+///
+
 /// tip
 
 先嘗試使用 `bump-pydantic`,如果測試通過且一切正常,你就能用一條指令完成遷移。✨
index 12fb7b8e87a9c59122f065281f4dc3bf6ed4aca8..72a806b4c1094749602944a624da48213df84af3 100644 (file)
@@ -1,8 +1,8 @@
 # 是否將輸入與輸出使用不同的 OpenAPI 結構描述 { #separate-openapi-schemas-for-input-and-output-or-not }
 
-自從 Pydantic v2 發佈後,生成的 OpenAPI 比以往更精確也更正確。😎
+自從 **Pydantic v2** 發佈後,生成的 OpenAPI 比以往更精確也更**正確**。😎
 
-實際上,在某些情況下,同一個 Pydantic 模型在 OpenAPI 中會同時有兩個 JSON Schema:分別用於輸入與輸出,這取決於它是否有預設值
+實際上,在某些情況下,同一個 Pydantic 模型在 OpenAPI 中會同時有**兩個 JSON Schema**:分別用於輸入與輸出,這取決於它是否有**預設值**
 
 來看看它如何運作,以及若需要時該如何調整。
 
 
 {* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
 
-...則 `description` 欄位將不是必填。因為它的預設值是 `None`。
+...則 `description` 欄位將**不是必填**。因為它的預設值是 `None`。
 
 ### 文件中的輸入模型 { #input-model-in-docs }
 
-你可以在文件中確認,`description` 欄位沒有紅色星號,表示不是必填:
+你可以在文件中確認,`description` 欄位沒有**紅色星號**,表示不是必填:
 
 <div class="screenshot">
 <img src="/img/tutorial/separate-openapi-schemas/image01.png">
@@ -34,7 +34,7 @@
 
 {* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
 
-...由於 `description` 有預設值,就算你沒有為該欄位回傳任何內容,它仍會有那個預設值
+...由於 `description` 有預設值,就算你**沒有為該欄位回傳任何內容**,它仍會有那個**預設值**
 
 ### 輸出回應資料的模型 { #model-for-output-response-data }
 
 <img src="/img/tutorial/separate-openapi-schemas/image02.png">
 </div>
 
-這代表該欄位一定會有值,只是有時候值可能是 `None`(在 JSON 中為 `null`)。
+這代表該欄位**一定會有值**,只是有時候值可能是 `None`(在 JSON 中為 `null`)。
 
-因此,使用你 API 的用戶端不必檢查值是否存在,可以假設該欄位一定存在;只是有些情況下它的值會是預設的 `None`。
+因此,使用你 API 的用戶端不必檢查值是否存在,可以**假設該欄位一定存在**;只是有些情況下它的值會是預設的 `None`。
 
-在 OpenAPI 中,描述這種情況的方式是將該欄位標記為必填,因為它一定存在。
+在 OpenAPI 中,描述這種情況的方式是將該欄位標記為**必填**,因為它一定存在。
 
-因此,同一個模型的 JSON Schema 會依用於輸入或輸出而不同:
+因此,同一個模型的 JSON Schema 會依用於**輸入或輸出**而不同:
 
-- 用於輸入時,`description` 不是必填
-- 用於輸出時,`description` 是必填(且可能為 `None`,在 JSON 中為 `null`)
+* 用於**輸入**時,`description` **不是必填**
+* 用於**輸出**時,`description` 是**必填**(且可能為 `None`,在 JSON 中為 `null`)
 
 ### 文件中的輸出模型 { #model-for-output-in-docs }
 
-你也可以在文件中檢視輸出模型,`name` 與 `description` 都以紅色星號標示為必填
+你也可以在文件中檢視輸出模型,`name` 與 `description` **兩者**都以**紅色星號**標示為**必填**
 
 <div class="screenshot">
 <img src="/img/tutorial/separate-openapi-schemas/image03.png">
 
 如果你查看 OpenAPI 中所有可用的結構描述(JSON Schema),會看到有兩個:`Item-Input` 與 `Item-Output`。
 
-對於 `Item-Input`,`description` 不是必填,沒有紅色星號。
+對於 `Item-Input`,`description` **不是必填**,沒有紅色星號。
 
-但對於 `Item-Output`,`description` 是必填,有紅色星號。
+但對於 `Item-Output`,`description` 是**必填**,有紅色星號。
 
 <div class="screenshot">
 <img src="/img/tutorial/separate-openapi-schemas/image04.png">
 </div>
 
-有了 Pydantic v2 的這個特性,你的 API 文件會更精確;若你有自動產生的用戶端與 SDK,它們也會更精確,提供更好的開發者體驗與一致性。🎉
+有了 **Pydantic v2** 的這個特性,你的 API 文件會更**精確**;若你有自動產生的用戶端與 SDK,它們也會更精確,提供更好的**開發者體驗**與一致性。🎉
 
 ## 不要分開結構描述 { #do-not-separate-schemas }
 
-不過,在某些情況下,你可能會希望輸入與輸出使用相同的結構描述
+不過,在某些情況下,你可能會希望**輸入與輸出使用相同的結構描述**
 
 最常見的情境是:你已經有一些自動產生的用戶端程式碼/SDK,目前還不想全部更新;也許之後會做,但不是現在。
 
-在這種情況下,你可以在 FastAPI 中透過參數 `separate_input_output_schemas=False` 停用這個功能。
+在這種情況下,你可以在 **FastAPI** 中透過參數 `separate_input_output_schemas=False` 停用這個功能。
 
 /// note
 
@@ -95,7 +95,7 @@
 
 ### 文件中輸入與輸出使用相同結構描述的模型 { #same-schema-for-input-and-output-models-in-docs }
 
-此時輸入與輸出將共用同一個模型結構描述,只有 `Item`,其中 `description` 不是必填
+此時輸入與輸出將共用同一個模型結構描述,只有 `Item`,其中 `description` **不是必填**
 
 <div class="screenshot">
 <img src="/img/tutorial/separate-openapi-schemas/image05.png">
index 5a45a69c7f52261f8ab789117a23d8c108b775e1..743357b96c8a4c734c3a2aa6f7d4d3696489763e 100644 (file)
@@ -277,7 +277,7 @@ INFO:     Application startup complete.
 <details markdown="1">
 <summary>關於指令 <code>fastapi dev</code>...</summary>
 
-指令 `fastapi dev` 會讀取你的 `main.py`,偵測其中的 **FastAPI** 應用,並使用 [Uvicorn](https://www.uvicorn.dev) 啟動伺服器。
\8c\87令 `fastapi dev` æ\9c\83è\87ªå\8b\95è®\80å\8f\96ä½ ç\9a\84 `main.py`ï¼\8cå\81µæ¸¬å\85¶ä¸­ç\9a\84 **FastAPI** æ\87\89ç\94¨ï¼\8c並使ç\94¨ [Uvicorn](https://www.uvicorn.dev) å\95\9få\8b\95伺æ\9c\8då\99¨ã\80\82
 
 預設情況下,`fastapi dev` 會在本機開發時啟用自動重新載入。
 
@@ -473,7 +473,7 @@ item: Item
 
 ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
 
-若想看包含更多功能的完整範例,請參考 <a href="https://fastapi.tiangolo.com/zh-hant/tutorial/">Tutorial - User Guide</a>。
+若想看包含更多功能的完整範例,請參考 <a href="https://fastapi.tiangolo.com/zh-hant/tutorial/">教學 - 使用者指南</a>。
 
 **劇透警告**:教學 - 使用者指南包含:
 
@@ -520,7 +520,7 @@ CLI 會自動偵測你的 FastAPI 應用並將其部署到雲端。若你尚未
 
 它把用 FastAPI 開發應用的**開發者體驗**帶到**部署**到雲端的流程中。🎉
 
-FastAPI Cloud 是「FastAPI 與好朋友們」這些開源專案的主要贊助與資金來源。✨
+FastAPI Cloud 是 *FastAPI 與好朋友們* 這些開源專案的主要贊助與資金來源。✨
 
 #### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }
 
index fc5c8e46556f49d718dfb3ddbc343e70128d3140..862417affb163520e62669cb99dcc8f281e4031a 100644 (file)
@@ -1,5 +1,6 @@
 # 全端 FastAPI 範本 { #full-stack-fastapi-template }
 
+
 範本通常附帶特定的設定,但設計上具有彈性且可自訂。這讓你可以依專案需求調整與擴充,因此非常適合作為起點。🏁
 
 你可以使用此範本快速起步,裡面已替你完成大量初始設定、安全性、資料庫,以及部分 API 端點。
index dc716026102dcbe9c20092d627b84c4a306c8ee1..29592176043eb577563ab9d9423215e4a388d868 100644 (file)
@@ -2,11 +2,11 @@
 
 Python 支援可選用的「型別提示」(也稱為「型別註記」)。
 
-這些「型別提示」或註記是一種特殊語法,用來宣告變數的<dfn title="例如:str、int、float、bool">型別</dfn>。
+這些 **「型別提示」** 或註記是一種特殊語法,用來宣告變數的<dfn title="例如:str、int、float、bool">型別</dfn>。
 
 為你的變數宣告型別後,編輯器與工具就能提供更好的支援。
 
-這裡只是關於 Python 型別提示的快速教學/複習。它只涵蓋使用在 **FastAPI** 時所需的最低限度...其實非常少。
+這裡只是關於 Python 型別提示的**快速教學/複習**。它只涵蓋使用在 **FastAPI** 時所需的最低限度...其實非常少。
 
 **FastAPI** 完全是以這些型別提示為基礎,並因此帶來許多優勢與好處。
 
@@ -137,7 +137,7 @@ John Doe
 
 ### `typing` 模組 { #typing-module }
 
-在一些其他情境中,你可能需要從標準程式庫的 `typing` 模組匯入一些東西,比如當你想宣告某個東西可以是「任何型別」時,可以用 `typing` 裡的 `Any`:
+在一些其他情境中,你可能需要從標準程式庫的 `typing` 模組匯入一些東西,比如當你想宣告某個東西可以是「任何型別」時,可以用 `Any`:
 
 ```python
 from typing import Any
@@ -151,7 +151,7 @@ def some_function(data: Any):
 
 有些型別可以在方括號中接收「型別參數」,以定義其內部元素的型別,例如「字串的 list」可以宣告為 `list[str]`。
 
-這些能接收型別參數的型別稱為「泛型(Generic types)」或「Generics」
+這些能接收型別參數的型別稱為 **泛型(Generic types)** 或 **Generics**
 
 你可以將相同的內建型別用作泛型(使用方括號並在裡面放型別):
 
@@ -221,7 +221,7 @@ def some_function(data: Any):
 
 #### Union { #union }
 
-你可以宣告一個變數可以是「多種型別」中的任一種,例如 `int` 或 `str`。
+你可以宣告一個變數可以是**多種型別**中的任一種,例如 `int` 或 `str`。
 
 要這麼定義,你使用<dfn title='也稱為「位元或運算子」,但在這裡與該含義無關'>豎線(`|`)</dfn>來分隔兩種型別。
 
@@ -263,9 +263,9 @@ def some_function(data: Any):
 
 <img src="/img/python-types/image06.png">
 
-請注意,這表示「`one_person` 是類別 `Person` 的『實例(instance)』」。
+請注意,這表示「`one_person` 是類別 `Person` 的**實例(instance)**」。
 
-並不是「`one_person` 就是名為 `Person` 的『類別(class)』」。
+並不是「`one_person` 就是名為 `Person` 的**類別(class)**」。
 
 ## Pydantic 模型 { #pydantic-models }
 
@@ -295,7 +295,7 @@ def some_function(data: Any):
 
 ## 含中繼資料的型別提示 { #type-hints-with-metadata-annotations }
 
-Python 也有一個功能,允許使用 `Annotated` 在這些型別提示中放入額外的<dfn title="關於資料的資料;在此情境下,是關於型別的資訊,例如描述。">中繼資料</dfn>
+Python 也有一個功能,允許使用 `Annotated` 在這些型別提示中放入**額外的<dfn title="關於資料的資料;在此情境下,是關於型別的資訊,例如描述。">中繼資料</dfn>**
 
 你可以從 `typing` 匯入 `Annotated`。
 
@@ -305,15 +305,15 @@ Python 本身不會對這個 `Annotated` 做任何事。對編輯器與其他工
 
 但你可以利用 `Annotated` 這個空間,來提供 **FastAPI** 額外的中繼資料,告訴它你希望應用程式如何運作。
 
-重要的是要記住,傳給 `Annotated` 的「第一個型別參數」才是「真正的型別」。其餘的,都是給其他工具用的中繼資料。
+重要的是要記住,傳給 `Annotated` 的**第一個*型別參數***才是**實際型別**。其餘的,都是給其他工具用的中繼資料。
 
 目前你只需要知道 `Annotated` 的存在,而且它是標準的 Python。😎
 
-之後你會看到它有多「強大」
+之後你會看到它有多**強大**
 
 /// tip | 提示
 
-因為這是「標準 Python」,所以你在編輯器、分析與重構程式碼的工具等方面,仍然能獲得「最佳的開發體驗」。✨
+因為這是**標準 Python**,所以你在編輯器、分析與重構程式碼的工具等方面,仍然能獲得**最佳的開發體驗**。✨
 
 而且你的程式碼也會與許多其他 Python 工具與程式庫非常相容。🚀
 
@@ -325,17 +325,17 @@ Python 本身不會對這個 `Annotated` 做任何事。對編輯器與其他工
 
 在 **FastAPI** 中,你用型別提示來宣告參數,然後你會得到:
 
-* 編輯器支援
-* 型別檢查
+* **編輯器支援**。
+* **型別檢查**。
 
 ...而 **FastAPI** 也會用同樣的宣告來:
 
-* 定義需求:來自請求的路徑參數、查詢參數、標頭、主體(body)、相依性等
-* 轉換資料:把請求中的資料轉成所需型別
-* 驗證資料:來自每個請求的資料:
-    * 當資料無效時,自動產生錯誤並回傳給用戶端
-* 使用 OpenAPI 書寫 API 文件
-    * 之後會由自動的互動式文件介面所使用
+* **定義需求**:來自請求的路徑參數、查詢參數、標頭、主體(body)、相依性等。
+* **轉換資料**:把請求中的資料轉成所需型別。
+* **驗證資料**:來自每個請求的資料:
+    * 當資料無效時,產生回傳給用戶端的**自動錯誤**。
+* 使用 OpenAPI **記錄** API
+    * 之後會由自動的互動式文件介面所使用
 
 這些現在聽起來可能有點抽象。別擔心。你會在[教學 - 使用者指南](tutorial/index.md)中看到它們的實際運作。
 
index 60dd4f350ab593611a0bed2c23a208f41398c93c..624b2c2bc2f890124967e58e5cdba44c93a5d843 100644 (file)
@@ -17,16 +17,16 @@ FastAPI 提供了一個方便的工具,讓你在維持彈性的同時,幫你
 ```
 .
 ├── app
-│   ├── __init__.py
-│   ├── main.py
-│   ├── dependencies.py
-│   └── routers
-│   │   ├── __init__.py
-│   │   ├── items.py
-│   │   └── users.py
-│   └── internal
-│       ├── __init__.py
-│       └── admin.py
+│   ├── __init__.py
+│   ├── main.py
+│   ├── dependencies.py
+│   └── routers
+│   │   ├── __init__.py
+│   │   ├── items.py
+│   │   └── users.py
+│   └── internal
+│       ├── __init__.py
+│       └── admin.py
 ```
 
 /// tip | 提示
@@ -542,6 +542,6 @@ router.include_router(other_router)
 
 請使用有文件記載的 API,例如路徑操作的裝飾器與 `.include_router()` 來新增路由與 routers。
 
-把 `router.routes` 視為較低階的路由樹結構,它可能同時包含路由定義與被納入的 routers,避免將它當成最終路徑操作的平lat清單來依賴。
+把 `router.routes` 視為較低階的路由樹結構,它可能同時包含路由定義與被納入的 routers,避免將它當成最終路徑操作的扁平清單來依賴。
 
 ///
index 161920acd9b136dd0747699f1926e05cde59acd6..4e2e6427cbc4566c65a324773f3e830e83b91248 100644 (file)
@@ -1,5 +1,6 @@
 # Body - 巢狀模型 { #body-nested-models }
 
+
 使用 **FastAPI**,你可以定義、驗證、文件化,並使用任意深度的巢狀模型(感謝 Pydantic)。
 
 ## 列表欄位 { #list-fields }
index aff55730bb2120280e7ac00d820ffa1072301ecb..f1ba8e954f67950f0b9901210095c13d73626fb4 100644 (file)
@@ -32,6 +32,7 @@
 
 {* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
 
+
 就和宣告查詢參數時一樣,當模型屬性有預設值時,它就不是必填;否則就是必填。使用 `None` 可使其成為選填。
 
 例如,上述模型對應的 JSON「`object`」(或 Python `dict`)如下:
 
 {* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
 
+
 ## 請求本文 + 路徑 + 查詢參數 { #request-body-path-query-parameters }
 
 你也可以同時宣告**本文**、**路徑**與**查詢**參數。
index 9501dec5cd434785bddac2d6a8f3d803ad2ccf34..a3254e3d197cd21e60aeb04b1ed1ffea182e5986 100644 (file)
@@ -1,5 +1,6 @@
 # 偵錯 { #debugging }
 
+
 你可以在編輯器中連接偵錯器,例如 Visual Studio Code 或 PyCharm。
 
 ## 呼叫 `uvicorn` { #call-uvicorn }
index 59d575fb0164d94208bf24756f69a5f9a4eb34cf..c41f3ba7d470d10738eb5f7b773d55ae1f3a501a 100644 (file)
@@ -234,6 +234,7 @@ participant operation as Path Operation
 含 `yield` 的相依隨時間演進,以涵蓋不同的使用情境並修正一些問題。
 
 如果你想了解在不同 FastAPI 版本中改了哪些內容,可以在進階指南中閱讀:[進階相依 — 含 `yield`、`HTTPException`、`except` 與背景任務的相依](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks)。
+
 ## 情境管理器 { #context-managers }
 
 ### 什麼是「情境管理器」 { #what-are-context-managers }
index a5573379d829d878baff602678e6a3dd44b02575..23c75323278808cb37ac6f5d3a826ef10c9debd7 100644 (file)
@@ -1,5 +1,6 @@
 # 額外的資料型別 { #extra-data-types }
 
+
 到目前為止,你一直在使用常見的資料型別,例如:
 
 * `int`
index f5509f531f6593ef6c877ad2a128ebea6b002640..162325e9d161ec2da14019914f38661d0937c23f 100644 (file)
@@ -4,9 +4,9 @@
 
 對使用者模型尤其如此,因為:
 
-* 「輸入模型」需要能包含密碼。
-* 「輸出模型」不應包含密碼。
-* 「資料庫模型」通常需要儲存雜湊後的密碼。
+* **輸入模型**需要能包含密碼。
+* **輸出模型**不應包含密碼。
+* **資料庫模型**通常需要儲存雜湊後的密碼。
 
 /// danger
 
@@ -140,7 +140,7 @@ UserInDB(
 
 ## 減少重複 { #reduce-duplication }
 
-減少程式碼重複是 FastAPI 的核心理念之一。
+減少程式碼重複是 **FastAPI** 的核心理念之一。
 
 因為重複的程式碼會提高發生錯誤、安全性問題、程式不同步(某處更新但其他處未更新)等風險。
 
@@ -176,7 +176,7 @@ UserInDB(
 
 此範例中,我們將 `Union[PlaneItem, CarItem]` 作為引數 `response_model` 的值。
 
-由於這裡是把它當作引數的「值」傳入,而非用於型別註記,因此即使在 Python 3.10 也必須使用 `Union`。
+由於這裡是把它當作**引數的值**傳入,而非放在**型別註記**中,因此即使在 Python 3.10 也必須使用 `Union`。
 
 若用於型別註記,則可以使用直線(|),如下:
 
@@ -184,7 +184,7 @@ UserInDB(
 some_variable: PlaneItem | CarItem
 ```
 
-但若寫成指定值 `response_model=PlaneItem | CarItem` 會發生錯誤,因為 Python 會嘗試在 `PlaneItem` 與 `CarItem` 之間執行「無效運算」,而非將其視為型別註記。
+但若寫成指定值 `response_model=PlaneItem | CarItem` 會發生錯誤,因為 Python 會嘗試在 `PlaneItem` 與 `CarItem` 之間執行**無效運算**,而非將其視為型別註記。
 
 ## 模型的清單 { #list-of-models }
 
@@ -208,4 +208,4 @@ some_variable: PlaneItem | CarItem
 
 依情境使用多個 Pydantic 模型並靈活繼承。
 
-當一個實體需要呈現不同「狀態」時,不必侷限於一個資料模型。例如使用者這個實體,可能有包含 `password`、包含 `password_hash`,或不含密碼等不同狀態。
+當一個實體需要呈現不同「狀態」時,不必侷限於一個資料模型。**使用者**「實體」是一個例子,可能有包含 `password`、包含 `password_hash`,或不含密碼等不同狀態。
index 8d644abd1489f3f89d9199d92f5b8b940d4f162e..bc023cc399c50edad92895f39638fdf0a7da70f8 100644 (file)
@@ -137,9 +137,9 @@ OpenAPI 為你的 API 定義了 API 的 schema。而該 schema 會包含你的 A
 
 #### OpenAPI 的用途 { #what-is-openapi-for }
 
-OpenAPI schema 驅動了兩個互動式文件系統。
+OpenAPI schema é©\85å\8b\95äº\86å\85§å»ºç\9a\84å\85©å\80\8bäº\92å\8b\95å¼\8fæ\96\87件系統ã\80\82
 
-而且有許多替代方案,所有這些都是基於 OpenAPI。你可以輕鬆地將任何這些替代方案添加到使用 **FastAPI** 建置的應用程式中。
+而且有數十種替代方案,所有這些都是基於 OpenAPI。你可以輕鬆地將任何這些替代方案加入到使用 **FastAPI** 建置的應用程式中。
 
 你也可以用它自動生成程式碼,讓用戶端與你的 API 通訊。例如前端、手機或物聯網(IoT)應用程式。
 
@@ -226,7 +226,7 @@ CLI 會自動偵測你的 FastAPI 應用並將它部署到雲端。若你尚未
 
 {* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}
 
-`FastAPI` 是一個 Python 類別,提供所有 API 的全部功能。
+`FastAPI` 是一個 Python 類別,提供你的 API 所需的所有功能。
 
 /// note | 技術細節
 
@@ -244,7 +244,7 @@ CLI 會自動偵測你的 FastAPI 應用並將它部署到雲端。若你尚未
 
 這將是你建立所有 API 的主要互動點。
 
-### 第三步:建立一個「路徑操作」 { #step-3-create-a-path-operation }
+### 第三步:建立一個*路徑操作* { #step-3-create-a-path-operation }
 
 #### 路徑 { #path }
 
@@ -256,7 +256,7 @@ CLI 會自動偵測你的 FastAPI 應用並將它部署到雲端。若你尚未
 https://example.com/items/foo
 ```
 
-……的路徑將會是:
+...的路徑將會是:
 
 ```
 /items/foo
@@ -281,7 +281,7 @@ https://example.com/items/foo
 * `PUT`
 * `DELETE`
 
-……以及更少見的:
+...以及更少見的:
 
 * `OPTIONS`
 * `HEAD`
@@ -305,14 +305,14 @@ https://example.com/items/foo
 
 我們將會稱它們為「**操作**」。
 
-#### 定義一個「路徑操作裝飾器」 { #define-a-path-operation-decorator }
+#### 定義一個*路徑操作裝飾器* { #define-a-path-operation-decorator }
 
 {* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
 
-`@app.get("/")` 告訴 **FastAPI** 那個函式負責處理請求:
+`@app.get("/")` 告訴 **FastAPI** 正下方的函式負責處理前往以下位置的請求:
 
 * 路徑 `/`
-* 使用 <dfn title="HTTP GET 方法"><code>get</code> 操作</dfn>
+* 使用 <dfn title="一個 HTTP GET 方法"><code>get</code> 操作</dfn>
 
 /// note | `@decorator` 說明
 
@@ -353,7 +353,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
 
 ///
 
-### 第四步:定義「路徑操作函式」 { #step-4-define-the-path-operation-function }
+### 第四步:定義**路徑操作函式** { #step-4-define-the-path-operation-function }
 
 這是我們的「**路徑操作函式**」:
 
@@ -377,7 +377,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
 
 /// note
 
-如果你不知道差別,請查看 [Async: *"In a hurry?"*](../async.md#in-a-hurry)。
+如果你不知道差別,請查看 [Async:*「很趕時間?」*](../async.md#in-a-hurry)。
 
 ///
 
@@ -399,11 +399,11 @@ Python 中的 `@something` 語法被稱為「裝飾器」。
 
 **[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的作者與團隊打造。
 
-å®\83è®\93你以æ\9c\80å°\8fç\9a\84æ\88\90æ\9c¬å®\8cæ\88\90 API 的**建置**、**部署**與**存取**流程。
+å®\83è®\93你以æ\9c\80å°\91ç\9a\84å¿\83å\8a\9bç°¡å\8c\96 API 的**建置**、**部署**與**存取**流程。
 
 它把用 FastAPI 開發應用的同樣**開發者體驗**帶到將應用**部署**到雲端的流程中。🎉
 
-FastAPI Cloud 也是「FastAPI 與其好友」這些開源專案的主要贊助與資金提供者。✨
+FastAPI Cloud 也是 *FastAPI 與其好友* 這些開源專案的主要贊助與資金提供者。✨
 
 #### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }
 
@@ -415,7 +415,7 @@ FastAPI 是開源並基於標準的。你可以把 FastAPI 應用部署到你選
 
 * 引入 `FastAPI`。
 * 建立一個 `app` 實例。
-* 寫一個「路徑操作裝飾器」,像是 `@app.get("/")`。
-* 定義一個「路徑操作函式」;例如,`def root(): ...`。
+* 寫一個**路徑操作裝飾器**,像是 `@app.get("/")`。
+* 定義一個**路徑操作函式**;例如,`def root(): ...`。
 * 使用命令 `fastapi dev` 執行開發伺服器。
 * 可選:使用 `fastapi deploy` 部署你的應用程式。
index b1ffd3e0387f8f03ead0be07728fdae056ea80bf..dc6d7a7cc3425d574ef5e98269ab6c6324677ca8 100644 (file)
 * 用戶端嘗試存取的項目不存在。
 * 等等。
 
-在這些情況下,通常會回傳範圍為 400(400 到 499)的 HTTP 狀態碼
+在這些情況下,通常會回傳範圍為 **400**(400 到 499)的 **HTTP 狀態碼**
 
 這類似於 200 範圍的 HTTP 狀態碼(200 到 299)。那些「200」狀態碼表示請求在某種程度上是「成功」的。
 
 400 範圍的狀態碼表示用戶端錯誤。
 
-還記得那些「404 Not Found」錯誤(和梗)嗎?
+還記得那些 **「404 Not Found」** 錯誤(和梗)嗎?
 
 ## 使用 `HTTPException` { #use-httpexception }
 
index e191215113ee4315993caa669240213773925f49..e20c9ca24d2151d7f8c459e8f6866dc37900ea8f 100644 (file)
@@ -98,4 +98,4 @@ FastAPI 提供了 [VS Code 官方擴充功能](https://marketplace.visualstudio.
 
 但首先你應該閱讀**教學 - 使用者指南**(你正在閱讀的內容)。
 
-它被設計成你可以使用**教學 - 使用者指南**來建立一個完整的應用程式,然後根據你的需求,使用一些額外的想法來擴展它。
+它被設計成你可以使用**教學 - 使用者指南**來建立一個完整的應用程式,然後根據你的需求,使用**進階使用者指南**中的一些額外想法,以不同方式擴展它。
index 6a54724a5db22a05ef1e08a9e7d31bfa8910882d..55fa4bdbf4c25b520b0fe5b44e784f1b3d172e66 100644 (file)
@@ -1,6 +1,6 @@
 # 中繼資料與文件 URL { #metadata-and-docs-urls }
 
-你可以在你的 FastAPI 應用程式中自訂多項中繼資料設定。
+你可以在你的 **FastAPI** 應用程式中自訂多項中繼資料設定。
 
 ## API 的中繼資料 { #metadata-for-api }
 
@@ -11,7 +11,7 @@
 | `title` | `str` | API 的標題。 |
 | `summary` | `str` | API 的簡短摘要。<small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small> |
 | `description` | `str` | API 的簡短說明。可使用 Markdown。 |
-| `version` | `string` | API 的版本號。這是你自己的應用程式版本,不是 OpenAPI 的版本,例如 `2.5.0`。 |
+| `version` | `str` | API 的版本號。這是你自己的應用程式版本,不是 OpenAPI 的版本,例如 `2.5.0`。 |
 | `terms_of_service` | `str` | 指向 API 服務條款的 URL。若提供,必須是 URL。 |
 | `contact` | `dict` | 對外公開的 API 聯絡資訊。可包含多個欄位。<details><summary><code>contact</code> 欄位</summary><table><thead><tr><th>參數</th><th>型別</th><th>說明</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>聯絡人/組織的識別名稱。</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>指向聯絡資訊的 URL。必須是 URL 格式。</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>聯絡人/組織的電子郵件地址。必須是電子郵件格式。</td></tr></tbody></table></details> |
 | `license_info` | `dict` | 對外公開的 API 授權資訊。可包含多個欄位。<details><summary><code>license_info</code> 欄位</summary><table><thead><tr><th>參數</th><th>型別</th><th>說明</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>必填</strong>(若有設定 <code>license_info</code>)。API 使用的授權名稱。</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API 的 [SPDX](https://spdx.org/licenses/) 授權表示式。<code>identifier</code> 欄位與 <code>url</code> 欄位互斥。<small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API 所採用授權的 URL。必須是 URL 格式。</td></tr></tbody></table></details> |
@@ -46,7 +46,7 @@
 
 每個 dictionary 可包含:
 
-* `name`(**必填**):一個 `str`,其值需與你在路徑操作與 `APIRouter`s 的 `tags` 參數中使用的標籤名稱相同。
+* `name`(**必填**):一個 `str`,其值需與你在*路徑操作*與 `APIRouter`s 的 `tags` 參數中使用的標籤名稱相同。
 * `description`:一個 `str`,為該標籤的簡短描述。可使用 Markdown,並會顯示在文件介面中。
 * `externalDocs`:一個 `dict`,描述外部文件,包含:
     * `description`:一個 `str`,外部文件的簡短描述。
@@ -70,7 +70,7 @@
 
 ### 使用你的標籤 { #use-your-tags }
 
-在你的路徑操作(以及 `APIRouter`s)上使用 `tags` 參數,將它們歸類到不同標籤下:
+在你的*路徑操作*(以及 `APIRouter`s)上使用 `tags` 參數,將它們歸類到不同標籤下:
 
 {* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
 
 
 你可以設定內建的兩個文件使用者介面:
 
-* Swagger UI:提供於 `/docs`。
+* **Swagger UI**:提供於 `/docs`。
     * 可用 `docs_url` 參數設定其 URL。
     * 設定 `docs_url=None` 可停用。
-* ReDoc:提供於 `/redoc`。
+* **ReDoc**:提供於 `/redoc`。
     * 可用 `redoc_url` 參數設定其 URL。
     * 設定 `redoc_url=None` 可停用。
 
index 8461f252158b73b7e5f4507da0de025a139fb80a..edd10178c85ea7bf9a045fc28671303ecfeb9a4a 100644 (file)
@@ -1,5 +1,6 @@
 # 路徑操作設定 { #path-operation-configuration }
 
+
 你可以在你的「路徑操作裝飾器」中傳入多個參數來進行設定。
 
 /// warning | 警告
index 1c247b0f8e1eb32b32a1e824dd1958798911815b..99690708ef47a7b5984469f6c86db6791eb7e527 100644 (file)
@@ -1,6 +1,6 @@
 # 查詢參數與字串驗證 { #query-parameters-and-string-validations }
 
-FastAPI 允許你為參數宣告額外的資訊與驗證。
+**FastAPI** 允許你為參數宣告額外的資訊與驗證。
 
 以下面這個應用為例:
 
@@ -18,14 +18,14 @@ FastAPI 會因為預設值是 `= None` 而知道 `q` 不是必填。
 
 ## 額外驗證 { #additional-validation }
 
-我們要強制:即使 `q` 是可選,只要提供了,長度就不能超過 50 個字元
+我們要強制:即使 `q` 是可選,只要提供了,**長度就不能超過 50 個字元**
 
 ### 匯入 `Query` 與 `Annotated` { #import-query-and-annotated }
 
 要達成這點,先匯入:
 
-- 從 `fastapi` 匯入 `Query`
-- 從 `typing` 匯入 `Annotated`
+* 從 `fastapi` 匯入 `Query`
+* 從 `typing` 匯入 `Annotated`
 
 {* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
 
@@ -69,19 +69,19 @@ q: Annotated[str | None] = None
 
 注意預設值仍然是 `None`,所以這個參數仍是可選。
 
-不過,現在在 `Annotated` 裡有 `Query(max_length=50)`,我們就告訴 FastAPI 要對這個值做「額外驗證」,最多 50 個字元即可。😎
+不過,現在在 `Annotated` 裡有 `Query(max_length=50)`,我們就告訴 FastAPI 要對這個值做**額外驗證**,最多 50 個字元即可。😎
 
 /// tip | 提示
 
-這裡用的是 `Query()`,因為這是「查詢參數」。稍後你會看到 `Path()`、`Body()`、`Header()`、`Cookie()` 等,它們也接受與 `Query()` 相同的參數。
+這裡用的是 `Query()`,因為這是**查詢參數**。稍後你會看到 `Path()`、`Body()`、`Header()`、`Cookie()` 等,它們也接受與 `Query()` 相同的參數。
 
 ///
 
 FastAPI 現在會:
 
-- 驗證資料,確保長度最多 50 個字元
-- 當資料不合法時,回給用戶端清楚的錯誤
-- 在 OpenAPI 的路徑操作中文件化該參數(因此會出現在自動文件 UI
+* **驗證**資料,確保長度最多 50 個字元
+* 當資料不合法時,回給用戶端**清楚的錯誤**
+* 在 OpenAPI schema *路徑操作*中**文件化**該參數(因此會出現在**自動文件 UI**
 
 ## 替代方式(舊):將 `Query` 作為預設值 { #alternative-old-query-as-the-default-value }
 
@@ -105,7 +105,8 @@ FastAPI 現在會:
 q: str | None = Query(default=None)
 ```
 
-…會讓參數變為可選、預設值是 `None`,等同於:
+...會讓參數變為可選、預設值是 `None`,等同於:
+
 
 ```Python
 q: str | None = None
@@ -119,7 +120,7 @@ q: str | None = None
 q: str | None = Query(default=None, max_length=50)
 ```
 
-這一樣會驗證資料、在資料不合法時顯示清楚錯誤,並在 OpenAPI 的路徑操作中文件化該參數。
+這一樣會驗證資料、在資料不合法時顯示清楚錯誤,並在 OpenAPI schema *路徑操作*中文件化該參數。
 
 ### 將 `Query` 作為預設值或放在 `Annotated` 中 { #query-as-the-default-value-or-in-annotated }
 
@@ -133,7 +134,7 @@ q: str | None = Query(default=None, max_length=50)
 q: Annotated[str, Query(default="rick")] = "morty"
 ```
 
-因為不清楚預設值到底該是 `"rick"` 還是 `"morty"`。
+...因為不清楚預設值到底該是 `"rick"` 還是 `"morty"`。
 
 因此,你可以(且更推薦)這樣寫:
 
@@ -141,7 +142,7 @@ q: Annotated[str, Query(default="rick")] = "morty"
 q: Annotated[str, Query()] = "rick"
 ```
 
-或在較舊的程式碼中你會看到:
+...或在較舊的程式碼中你會看到:
 
 ```Python
 q: str = Query(default="rick")
@@ -149,13 +150,13 @@ q: str = Query(default="rick")
 
 ### `Annotated` 的優點 { #advantages-of-annotated }
 
-建議使用 `Annotated`,而不是在函式參數上使用(舊式的)預設值寫法,理由很多,且更好。🤓
+建議**使用 `Annotated`**,而不是在函式參數上使用預設值寫法,理由很多,且**更好**。🤓
 
-函式參數的「預設值」就是「實際的預設值」,這在 Python 的直覺上更一致。😌
+函式參數的**預設值**就是**實際的預設值**,這在 Python 的直覺上更一致。😌
 
-你也可以在沒有 FastAPI 的其他地方「直接呼叫」同一個函式,而且能「如預期」運作。若有「必填」參數(沒有預設值),你的「編輯器」會提示錯誤,「Python」在執行時也會抱怨你未傳遞必填參數。
+你也可以在沒有 FastAPI 的**其他地方**「**呼叫**」同一個函式,而且能「**如預期**」運作。若有**必填**參數(沒有預設值),你的**編輯器**會提示錯誤,**Python** 在執行時也會抱怨你未傳遞必填參數。
 
-若不使用 `Annotated`、改用「(舊式)預設值」寫法,你在沒有 FastAPI 的「其他地方」呼叫該函式時,就得「記得」傳入正確參數,否則值會和預期不同(例如會得到 `QueryInfo` 或類似的東西,而不是 `str`)。你的編輯器不會提示,Python 執行該函式時也不會抱怨,只有在內部操作失敗時才會出錯。
+若不使用 `Annotated`、改用**(舊式)預設值**寫法,你在沒有 FastAPI 的**其他地方**呼叫該函式時,就得**記得**傳入正確參數,否則值會和預期不同(例如會得到 `QueryInfo` 或類似的東西,而不是 `str`)。你的編輯器不會提示,Python 執行該函式時也不會抱怨,只有在內部操作失敗時才會出錯。
 
 因為 `Annotated` 可以有多個中繼資料註解,你甚至可以用同一個函式配合其他工具,例如 [Typer](https://typer.tiangolo.com/)。🚀
 
@@ -167,19 +168,19 @@ q: str = Query(default="rick")
 
 ## 加入正規表示式 { #add-regular-expressions }
 
-你可以定義參數必須符合的 <dfn title="正規表示式(regex、regexp)是一組用於定義字串搜尋樣式的字元序列。">正規表示式</dfn> `pattern`:
+你可以定義參數必須符合的 <dfn title="正規表示式、regex 或 regexp 是一組用於定義字串搜尋樣式的字元序列。">正規表示式</dfn> `pattern`:
 
 {* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
 
 這個特定的正規表示式樣式會檢查收到的參數值是否:
 
-- `^`:以後續的字元開頭,前面不能有其他字元。
-- `fixedquery`:必須正好等於 `fixedquery`。
-- `$`:在此結束,`fixedquery` 後面不能再有其他字元。
+* `^`:以後續的字元開頭,前面不能有其他字元。
+* `fixedquery`:必須正好等於 `fixedquery`。
+* `$`:在此結束,`fixedquery` 後面不能再有其他字元。
 
-如果你對「正規表示式」感到困惑,別擔心。這對很多人來說都不容易。你仍然可以先不使用正規表示式就完成很多事情。
+如果你對所有這些**「正規表示式」**概念感到困惑,別擔心。這對很多人來說都不容易。你仍然可以先不使用正規表示式就完成很多事情。
 
-現在你知道,當你需要它們時,可以在 FastAPI 中使用它們。
+現在你知道,當你需要它們時,可以在 **FastAPI** 中使用它們。
 
 ## 預設值 { #default-values }
 
@@ -235,13 +236,13 @@ q: Annotated[str | None, Query(min_length=3)] = None
 
 {* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
 
-若使用這樣的 URL:
+接著,若使用這樣的 URL:
 
 ```
 http://localhost:8000/items/?q=foo&q=bar
 ```
 
-你會在路徑操作函式的參數 `q` 中,收到多個 `q` 查詢參數的值(`foo` 與 `bar`),以 Python 的 `list` 形式。
+你會在*路徑操作函式*的*函式參數* `q` 中,收到多個 `q` *查詢參數*的值(`foo` 與 `bar`),以 Python 的 `list` 形式。
 
 因此,對該 URL 的回應會是:
 
@@ -276,7 +277,7 @@ http://localhost:8000/items/?q=foo&q=bar
 http://localhost:8000/items/
 ```
 
-`q` 的預設值會是:`["foo", "bar"]`,而回應會是:
+`q` 的預設值會是:`["foo", "bar"]`,而你的回應會是:
 
 ```JSON
 {
@@ -359,15 +360,15 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
 
 ## 從 OpenAPI 排除參數 { #exclude-parameters-from-openapi }
 
-若要把某個查詢參數從產生的 OpenAPI(以及自動文件系統)中排除,將 `Query` 的 `include_in_schema` 設為 `False`:
+若要把某個查詢參數從產生的 OpenAPI schema(以及自動文件系統)中排除,將 `Query` 的 `include_in_schema` 設為 `False`:
 
 {* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
 
 ## 自訂驗證 { #custom-validation }
 
-有時你需要做一些上述參數無法處理的「自訂驗證」
+有時你需要做一些上述參數無法處理的**自訂驗證**
 
-這種情況下,你可以使用「自訂驗證函式」,它會在一般驗證之後套用(例如先確認值是 `str` 之後)。
+這種情況下,你可以使用**自訂驗證函式**,它會在一般驗證之後套用(例如先確認值是 `str` 之後)。
 
 你可以在 `Annotated` 中使用 [Pydantic 的 `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) 來達成。
 
@@ -389,15 +390,15 @@ Pydantic 也有 [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/va
 
 /// tip | 提示
 
-如果你需要做任何需要與「外部元件」溝通的驗證(例如資料庫或其他 API),應該改用「FastAPI 依賴」(FastAPI Dependencies),你稍後會學到。
+如果你需要做任何需要與**外部元件**溝通的驗證(例如資料庫或其他 API),應該改用 **FastAPI Dependencies**,你稍後會學到。
 
-這些自訂驗證器適用於只需使用請求中「同一份資料」即可完成的檢查。
+這些自訂驗證器適用於只需使用請求中**同一份資料**即可完成的檢查。
 
 ///
 
 ### 理解這段程式碼 { #understand-that-code }
 
-重點就是在 `Annotated` 中使用「`AfterValidator` 搭配函式」。如果你願意,可以略過這一節。🤸
+重點就是在 `Annotated` 中使用 **`AfterValidator` 搭配函式**。如果你願意,可以略過這一節。🤸
 
 ---
 
@@ -415,13 +416,13 @@ Pydantic 也有 [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/va
 
 我們用 `list(data.items())` 把這個可疊代物件轉成正式的 `list`。
 
-接著用 `random.choice()` 從清單中取得一個「隨機值」,也就是一個 `(id, name)` 的 tuple。可能像是 `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`。
+接著用 `random.choice()` 從清單中取得一個**隨機值**,也就是一個 `(id, name)` 的 tuple。可能像是 `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`。
 
-然後把這個 tuple 的兩個值分別指定給變數 `id` 和 `name`。
+然後把這個 tuple 的**兩個值分別指定**給變數 `id` 和 `name`。
 
 因此,即使使用者沒有提供 item ID,仍然會收到一個隨機建議。
 
-……而這全部只用一行簡單的程式碼完成。🤯 你不愛 Python 嗎?🐍
+...而這全部只用**一行簡單的程式碼**完成。🤯 你不愛 Python 嗎?🐍
 
 {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
 
@@ -431,16 +432,16 @@ Pydantic 也有 [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/va
 
 通用的驗證與中繼資料:
 
-- `alias`
-- `title`
-- `description`
-- `deprecated`
+* `alias`
+* `title`
+* `description`
+* `deprecated`
 
 字串專用的驗證:
 
-- `min_length`
-- `max_length`
-- `pattern`
+* `min_length`
+* `max_length`
+* `pattern`
 
 使用 `AfterValidator` 的自訂驗證。
 
index 24b0cb4049a9cc4ec7780b13e9a134c67192fff8..86cf60a5ae410f69c36cdde09469c4b4648d5ce1 100644 (file)
@@ -67,7 +67,7 @@ http://127.0.0.1:8000/items/?skip=20
 
 /// tip | 提示
 
-另外請注意,FastAPI 能辨識出路徑參數 `item_id` 是路徑參數,而 `q` 不是,因此 `q` 會被當作查詢參數。
+另外請注意,**FastAPI** 能辨識出路徑參數 `item_id` 是路徑參數,而 `q` 不是,因此 `q` 會被當作查詢參數。
 
 ///
 
@@ -109,9 +109,10 @@ http://127.0.0.1:8000/items/foo?short=yes
 
 或任何其他大小寫變化(全大寫、首字母大寫等),你的函式會將參數 `short` 視為 `bool` 值 `True`。否則為 `False`。
 
+
 ## 多個路徑與查詢參數 { #multiple-path-and-query-parameters }
 
-你可以同時宣告多個路徑參數與查詢參數,FastAPI 會自動分辨。
+你可以同時宣告多個路徑參數與查詢參數,**FastAPI** 會自動分辨。
 
 而且不必按特定順序宣告。
 
index 1d95bf0cd4a52c433d61f70ba0ef3d1409f9c4e7..979a579ebdeecc3025ac7c50bbea71d20b1206c4 100644 (file)
@@ -1,5 +1,6 @@
 # 請求中的檔案 { #request-files }
 
+
 你可以使用 `File` 定義由用戶端上傳的檔案。
 
 /// note
index 28d50c3af9debe83fc7cc234147c89a10074bbfc..5907791682e2a2634ead30da339f31055bc23883 100644 (file)
@@ -1,5 +1,6 @@
 # 表單資料 { #form-data }
 
+
 當你需要接收表單欄位而不是 JSON 時,可以使用 `Form`。
 
 /// note
index 9ed047fa5985d1969f5c4d8a3be17e37306a6cfc..d649dc7855ded1000060bbdb068b3430b630e19f 100644 (file)
@@ -1,5 +1,6 @@
 # 回應狀態碼 { #response-status-code }
 
+
 就像你可以指定回應模型一樣,你也可以在任一個「路徑操作(path operation)」的參數 `status_code` 中宣告回應所使用的 HTTP 狀態碼:
 
 * `@app.get()`
index 01c4a217a0ec25ca8726c88a59f799d3ee0cc782..8cca5003a0f20feafe09f1bb44deb216ea4750f9 100644 (file)
@@ -10,7 +10,7 @@
 
 {* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
 
-這些額外資訊會原封不動加入該模型輸出的 JSON Schema,並且會用在 API 文件裡。
+這些額外資訊會原封不動加入該模型輸出的 **JSON Schema**,並且會用在 API 文件裡。
 
 你可以使用屬性 `model_config`(接收一個 `dict`),詳見 [Pydantic 文件:Configuration](https://docs.pydantic.dev/latest/api/config/)。
 
@@ -135,7 +135,7 @@ OpenAPI 3.1.0(自 FastAPI 0.99.0 起使用)新增了對 `examples` 的支援
 
 以下是關於 **JSON Schema** 與 **OpenAPI** 標準的技術細節。
 
-å¦\82æ\9e\9cä¸\8aé\9d¢ç\9a\84å\81\9aæ³\95å°\8dä½ å·²ç¶\93足夠å\8f¯ç\94¨ï¼\8cå°±ä¸\8dé\9c\80è¦\81é\80\99äº\9bç´°ç¯\80ï¼\8cå\84\98管直接跳過。
+å¦\82æ\9e\9cä¸\8aé\9d¢ç\9a\84å\81\9aæ³\95å°\8dä½ å·²ç¶\93足夠å\8f¯ç\94¨ï¼\8cå°±ä¸\8dé\9c\80è¦\81é\80\99äº\9bç´°ç¯\80ï¼\8cå\8f¯ä»¥直接跳過。
 
 ///
 
index b7db93b506a2c9c27033498ce78291da3a9cf561..7640a455640569a83ed39d37f9d87c4eefff200d 100644 (file)
@@ -1,16 +1,16 @@
 # 安全性 - 入門 { #security-first-steps }
 
-想像你有一個部署在某個網域的後端 API。
+想像你有一個部署在某個網域的 **後端** API。
 
-還有一個前端在另一個網域,或同一網域的不同路徑(或是行動應用程式)。
+還有一個 **前端** 在另一個網域,或同一網域的不同路徑(或是行動應用程式)。
 
-你希望前端能用使用者名稱與密碼向後端進行身分驗證。
+你希望前端能用**使用者名稱**與**密碼**向後端進行身分驗證。
 
-我們可以用 OAuth2 搭配 FastAPI 來實作。
+我們可以用 **OAuth2** 搭配 **FastAPI** 來實作。
 
 但不必通讀整份冗長規格只為了找出你需要的幾個重點。
 
-就用 FastAPI 提供的工具處理安全性。
+就用 **FastAPI** 提供的工具處理安全性。
 
 ## 看起來如何 { #how-it-looks }
 
@@ -26,7 +26,7 @@
 
 /// note
 
-當你使用 `pip install "fastapi[standard]"` 指令安裝時,[`python-multipart`](https://github.com/Kludex/python-multipart) 套件會隨 FastAPI 自動安裝。
+當你使用 `pip install "fastapi[standard]"` 指令安裝時,[`python-multipart`](https://github.com/Kludex/python-multipart) 套件會隨 **FastAPI** 自動安裝。
 
 不過若只執行 `pip install fastapi`,預設不會包含 `python-multipart`。
 
@@ -36,7 +36,7 @@
 $ pip install python-multipart
 ```
 
-因為 OAuth2 會以「form data」傳送 `username` 與 `password`。
+因為 **OAuth2** 會以「form data」傳送 `username` 與 `password`。
 
 ///
 
@@ -62,9 +62,9 @@ $ fastapi dev
 
 /// tip | Authorize 按鈕!
 
-你會看到一個新的「Authorize」按鈕。
+你已經有一個亮眼的全新「Authorize」按鈕。
 
-而你的「路徑操作」右上角也會出現一個小鎖頭可以點擊。
+而你的 *路徑操作* 右上角也會出現一個小鎖頭可以點擊。
 
 ///
 
@@ -94,29 +94,29 @@ $ fastapi dev
 
 OAuth2 的設計讓後端或 API 可以獨立於執行使用者驗證的伺服器。
 
-但在這個例子中,同一個 FastAPI 應用會同時處理 API 與驗證。
+但在這個例子中,同一個 **FastAPI** 應用會同時處理 API 與驗證。
 
 簡化來看流程如下:
 
 - 使用者在前端輸入 `username` 與 `password`,按下 `Enter`。
 - 前端(在使用者的瀏覽器中執行)把 `username` 與 `password` 傳到我們 API 的特定 URL(在程式中宣告為 `tokenUrl="token"`)。
-- API 檢查 `username` 與 `password`,並回一個「token(權杖)」(我們還沒實作這部分)。
+- API 檢查 `username` 與 `password`,並回一個「token(權杖)」(我們還沒實作這部分)。
     - 「token(權杖)」就是一段字串,之後可用來識別並驗證此使用者。
     - 通常 token 會設定一段時間後失效。
         - 因此使用者之後需要重新登入。
         - 若 token 被竊取,風險也較低;它不像永遠有效的萬用鑰匙(多數情況下)。
 - 前端會暫存這個 token。
-- 使用者在前端點擊前往其他頁面/區段。
+- 使用者在前端點擊,前往前端網頁應用程式的另一個區段。
 - 前端需要再向 API 取得資料。
     - 但該端點需要驗證。
     - 因此為了向 API 驗證,請求會帶上一個 `Authorization` 標頭,值為 `Bearer ` 加上 token。
     - 例如 token 是 `foobar`,則 `Authorization` 標頭內容為:`Bearer foobar`。
 
-## FastAPI 的 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }
+## **FastAPI** 的 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }
 
-FastAPI 提供多層抽象的工具來實作這些安全機制。
+**FastAPI** 提供多層抽象的工具來實作這些安全機制。
 
-本例將使用 OAuth2 的 Password 流程,並以 Bearer token 進行驗證;我們會用 `OAuth2PasswordBearer` 類別來完成。
+本例將使用 **OAuth2** 的 **Password** 流程,並以 **Bearer** token 進行驗證;我們會用 `OAuth2PasswordBearer` 類別來完成。
 
 /// note
 
@@ -126,7 +126,7 @@ FastAPI 提供多層抽象的工具來實作這些安全機制。
 
 通常對多數情境也足夠,除非你是 OAuth2 專家並確信有更適合你的選項。
 
-在那種情況下,FastAPI 也提供相應工具讓你自行組合。
+在那種情況下,**FastAPI** 也提供相應工具讓你自行組合。
 
 ///
 
@@ -144,7 +144,7 @@ FastAPI 提供多層抽象的工具來實作這些安全機制。
 
 ///
 
-這個參數不會建立該端點/「路徑操作」,而是宣告 `/token` 將是客戶端用來取得 token 的 URL。這些資訊會出現在 OpenAPI,並被互動式 API 文件系統使用。
+這個參數不會建立該端點 / *路徑操作*,而是宣告 `/token` 將是客戶端用來取得 token 的 URL。這些資訊會出現在 OpenAPI,並被互動式 API 文件系統使用。
 
 我們很快也會建立實際的路徑操作。
 
@@ -172,15 +172,15 @@ oauth2_scheme(some, parameters)
 
 {* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
 
-此相依性會提供一個 `str`,指派給「路徑操作函式」的參數 `token`。
+此相依性會提供一個 `str`,指派給 *路徑操作函式* 的參數 `token`。
 
-FastAPI 會知道可以使用這個相依性,在 OpenAPI(以及自動產生的 API 文件)中定義一個「安全性方案」。
+**FastAPI** 會知道可以使用這個相依性,在 OpenAPI schema(以及自動產生的 API 文件)中定義一個「安全性方案」。
 
 /// note | 技術細節
 
-FastAPI 之所以知道可以用(相依性中宣告的)`OAuth2PasswordBearer` 類別,在 OpenAPI 中定義安全性方案,是因為它繼承自 `fastapi.security.oauth2.OAuth2`,而後者又繼承自 `fastapi.security.base.SecurityBase`。
+**FastAPI** 之所以知道可以用(相依性中宣告的)`OAuth2PasswordBearer` 類別,在 OpenAPI 中定義安全性方案,是因為它繼承自 `fastapi.security.oauth2.OAuth2`,而後者又繼承自 `fastapi.security.base.SecurityBase`。
 
-所有能與 OpenAPI(以及自動 API 文件)整合的安全工具都繼承自 `SecurityBase`,FastAPI 才能知道如何把它們整合進 OpenAPI。
+所有能與 OpenAPI(以及自動 API 文件)整合的安全工具都繼承自 `SecurityBase`,**FastAPI** 才能知道如何把它們整合進 OpenAPI。
 
 ///
 
@@ -188,7 +188,7 @@ FastAPI 之所以知道可以用(相依性中宣告的)`OAuth2PasswordBearer
 
 它會從請求中尋找 `Authorization` 標頭,檢查其值是否為 `Bearer ` 加上一段 token,並將該 token 以 `str` 回傳。
 
-若未找到 `Authorization` 標頭,或其值不是 `Bearer ` token,則會直接回傳 401(`UNAUTHORIZED`)錯誤
+若未找到 `Authorization` 標頭,或其值不是 `Bearer ` token,則會直接回應 401 狀態碼錯誤(`UNAUTHORIZED`)
 
 你不必再自行檢查 token 是否存在;你可以確信只要你的函式被執行,該 token 參數就一定會是 `str`。
 
index c17b6468e1c197b9835746d6a7ab5b37f08e02d5..5309d78c030b788175561b03dfb9e58ba37545e2 100644 (file)
@@ -14,7 +14,7 @@
 
 就像用 Pydantic 宣告請求體一樣,我們也可以在其他地方使用它:
 
-{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:16] *}
 
 ## 建立 `get_current_user` 依賴 { #create-a-get-current-user-dependency }
 
index dba108c7493e4d72905d6cc4a2fdea2c5208adef..dc75092b4e95667a1c3062ec695717b4ed5a99c7 100644 (file)
@@ -120,7 +120,7 @@ pwdlib 也支援 bcrypt 雜湊演算法,但不包含傳統(legacy)演算
 
 當以不存在於資料庫的使用者名稱呼叫 `authenticate_user` 時,我們仍然會拿一個假的雜湊去跑一次 `verify_password`。
 
-這可確保無論使用者名稱是否有效,端點的回應時間都大致相同,避免可用來枚舉既有使用者名稱的「計時攻擊」(timing attacks)。
+這可確保無論使用者名稱是否有效,端點的回應時間都大致相同,避免可用來枚舉既有使用者名稱的 **計時攻擊**(timing attacks)。
 
 /// note | 注意
 
@@ -168,7 +168,7 @@ $ openssl rand -hex 32
 
 {* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
 
-## 更新 `/token` 路徑操作 { #update-the-token-path-operation }
+## 更新 `/token` *路徑操作* { #update-the-token-path-operation }
 
 用權杖有效期建立一個 `timedelta`。
 
index de0fe386d52ab242d6a58a9f2c4278d67c5288d6..2b29daa0d6888d6d1ac16ba845964c290b9c4a07 100644 (file)
@@ -132,7 +132,7 @@ OAuth2 規範中,當使用「password flow」(我們現在使用的)時,
 
 `UserInDB(**user_dict)` 的意思是:
 
-把 `user_dict` 的鍵和值直接當作具名參數傳入,等同於:
+*把 `user_dict` 的鍵和值直接當作具名參數傳入,等同於:*
 
 ```Python
 UserInDB(
@@ -146,7 +146,7 @@ UserInDB(
 
 /// note
 
-想更完整地了解 `**user_dict`,請回到[**額外模型** 的文件](../extra-models.md#about-user-in-dict)。
+想更完整地了解 `**user_dict`,請回到[**額外模型** 的文件](../extra-models.md#about-user-in-model-dump)。
 
 ///
 
index a37e164321ffccd0c004253fdf09298e6d829856..3a0e43d844a1878e60d289b7dc6a7db16d14c578 100644 (file)
@@ -1,10 +1,10 @@
 # SQL(關聯式)資料庫 { #sql-relational-databases }
 
-FastAPI 不強制你使用 SQL(關聯式)資料庫。你可以使用任何你想要的資料庫
+**FastAPI** 不強制你使用 SQL(關聯式)資料庫。但你可以使用**任何你想要的資料庫**
 
 這裡我們會用 [SQLModel](https://sqlmodel.tiangolo.com/) 作為範例。
 
-SQLModel 建立在 [SQLAlchemy](https://www.sqlalchemy.org/) 與 Pydantic 之上。它由 FastAPI 的作者開發,非常適合需要使用 SQL 資料庫的 FastAPI 應用。
+**SQLModel** 建立在 [SQLAlchemy](https://www.sqlalchemy.org/) 與 Pydantic 之上。它由 **FastAPI** 的作者開發,非常適合需要使用 **SQL 資料庫**的 FastAPI 應用。
 
 /// tip | 提示
 
@@ -12,7 +12,7 @@ SQLModel 建立在 [SQLAlchemy](https://www.sqlalchemy.org/) 與 Pydantic 之上
 
 ///
 
-因為 SQLModel 建立在 SQLAlchemy 之上,你可以輕鬆使用 SQLAlchemy 所支援的任何資料庫(因此 SQLModel 也支援),例如:
+因為 SQLModel 建立在 SQLAlchemy 之上,你可以輕鬆使用 SQLAlchemy 所支援的**任何資料庫**(因此 SQLModel 也支援),例如:
 
 * PostgreSQL
 * MySQL
@@ -20,17 +20,17 @@ SQLModel 建立在 [SQLAlchemy](https://www.sqlalchemy.org/) 與 Pydantic 之上
 * Oracle
 * Microsoft SQL Server,等等。
 
-在這個範例中,我們會使用 SQLite,因為它只用到單一檔案,而且 Python 內建支援。你可以直接複製這個範例並原樣執行。
+在這個範例中,我們會使用 **SQLite**,因為它只用到單一檔案,而且 Python 內建支援。你可以直接複製這個範例並原樣執行。
 
-之後,在你的正式環境應用中,你可能會想使用像 PostgreSQL 這類的資料庫伺服器。
+之後,在你的正式環境應用中,你可能會想使用像 **PostgreSQL** 這類的資料庫伺服器。
 
 /// tip | 提示
 
-有一個包含 FastAPI 與 PostgreSQL 的官方專案腳手架,還有前端與更多工具:[https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)
+有一個包含 **FastAPI** 與 **PostgreSQL** 的官方專案產生器,還有前端與更多工具:[https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)
 
 ///
 
-這是一份非常簡短的教學,如果你想更全面學習資料庫、SQL,或更進階的功能,請參考 [SQLModel 文件](https://sqlmodel.tiangolo.com/)。
+這是一份非常簡單且簡短的教學,如果你想更全面學習資料庫、SQL,或更進階的功能,請參考 [SQLModel 文件](https://sqlmodel.tiangolo.com/)。
 
 ## 安裝 `SQLModel` { #install-sqlmodel }
 
@@ -47,9 +47,9 @@ $ pip install sqlmodel
 
 ## 建立只有單一模型的應用 { #create-the-app-with-a-single-model }
 
-我們先用單一 SQLModel 模型建立這個應用的最簡版。
+我們先用單一 **SQLModel** 模型建立這個應用的最簡版。
 
-接著我們會在下方用多個模型來提升安全性與彈性。🤓
+接著我們會在下方用**多個模型**來提升安全性與彈性。🤓
 
 ### 建立模型 { #create-models }
 
@@ -57,43 +57,43 @@ $ pip install sqlmodel
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
 
-`Hero` é¡\9eå\88¥è\88\87 Pydantic æ¨¡å\9e\8bé\9d\9e常ç\9b¸ä¼¼ï¼\88äº\8b實ä¸\8aï¼\8cå\9c¨åº\95層å®\83å°±æ\98¯ä¸\80å\80\8b Pydantic æ¨¡å\9e\8b)。
+`Hero` é¡\9eå\88¥è\88\87 Pydantic æ¨¡å\9e\8bé\9d\9e常ç\9b¸ä¼¼ï¼\88äº\8b實ä¸\8aï¼\8cå\9c¨åº\95層å®\83å\85¶å¯¦*å°±æ\98¯ä¸\80å\80\8b Pydantic æ¨¡å\9e\8b*)。
 
 有幾點差異:
 
-* `table=True` 告訴 SQLModel 這是一個「資料表模型」(table model),它應該代表 SQL 資料庫中的一個資料表,而不僅僅是「資料模型」(就像一般的 Pydantic 類別)。
+* `table=True` 告訴 SQLModel 這是一個*資料表模型*(table model),它應該代表 SQL 資料庫中的一個**資料表**,而不僅僅是*資料模型*(就像一般的 Pydantic 類別)。
 
-* `Field(primary_key=True)` 告訴 SQLModel,`id` 是 SQL 資料庫中的「主鍵」。 (你可以在 SQLModel 文件中進一步了解 SQL 主鍵)
+* `Field(primary_key=True)` 告訴 SQLModel,`id` 是 SQL 資料庫中的**主鍵**(你可以在 SQLModel 文件中進一步了解 SQL 主鍵)。
 
-    注意:我們在主鍵欄位使用 `int | None`,這樣在 Python 程式碼中我們可以「在沒有 `id` 的情況下建立物件」(`id=None`),假設資料庫在儲存時會「自動產生」。SQLModel 瞭解資料庫會提供 `id`,並且在資料庫綱要中「將該欄位定義為非空的 `INTEGER`」。詳情請見 [SQLModel 文件:主鍵](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id)。
+    **注意:** 我們在主鍵欄位使用 `int | None`,這樣在 Python 程式碼中我們可以*在沒有 `id` 的情況下建立物件*(`id=None`),假設資料庫在儲存時會*自動產生*。SQLModel 瞭解資料庫會提供 `id`,並且在資料庫綱要中*將該欄位定義為非空的 `INTEGER`*。詳情請見 [SQLModel 文件:主鍵](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id)。
 
-* `Field(index=True)` 告訴 SQLModel 應為此欄位建立「SQL 索引」,以便在用此欄位過濾讀取資料時更快查詢。
+* `Field(index=True)` 告訴 SQLModel 應為此欄位建立 **SQL 索引**,以便在用此欄位過濾讀取資料時更快查詢。
 
     SQLModel 會知道宣告為 `str` 的欄位在 SQL 中會是 `TEXT`(或 `VARCHAR`,依資料庫而定)。
 
 ### 建立引擎 { #create-an-engine }
 
-SQLModel 的 `engine`(底層實際上是 SQLAlchemy 的 `engine`)是用來「維護與資料庫連線」的東西。
+SQLModel 的 `engine`(底層實際上是 SQLAlchemy 的 `engine`)是用來**維護與資料庫連線**的東西。
 
-你的程式中應該只有「單一 `engine` 物件」來連到同一個資料庫。
+你的程式中應該只有**單一 `engine` 物件**來連到同一個資料庫。
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
 
-使用 `check_same_thread=False` 允許 FastAPI 在不同執行緒中使用同一個 SQLite 資料庫。這是必要的,因為「單一請求」可能會使用「多個執行緒」(例如在依賴項中)。
+使用 `check_same_thread=False` 允許 FastAPI 在不同執行緒中使用同一個 SQLite 資料庫。這是必要的,因為**單一請求**可能會使用**多個執行緒**(例如在依賴項中)。
 
-別擔心,依照我們的程式結構,稍後我們會確保「每個請求只使用單一 SQLModel 的 session」,這其實就是 `check_same_thread` 想要達成的事。
+別擔心,依照我們的程式結構,稍後我們會確保**每個請求只使用單一 SQLModel 的 *session***,這其實就是 `check_same_thread` 想要達成的事。
 
 ### 建立資料表 { #create-the-tables }
 
-接著我們新增一個函式,使用 `SQLModel.metadata.create_all(engine)` 為所有「資料表模型」建立資料表
+接著我們新增一個函式,使用 `SQLModel.metadata.create_all(engine)` 為所有*資料表模型* **建立資料表**
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
 
 ### 建立 Session 依賴 { #create-a-session-dependency }
 
-「`Session`」會在記憶體中保存物件並追蹤資料需要的任何變更,然後透過「`engine`」與資料庫溝通。
+**`Session`** 會在記憶體中保存**物件**並追蹤資料需要的任何變更,然後透過 **`engine`** 與資料庫溝通。
 
-我們會用 `yield` 建立一個 FastAPI 的「依賴」,為每個請求提供一個新的 `Session`。這可確保每個請求只使用單一的 session。🤓
+我們會用 `yield` 建立一個 FastAPI 的**依賴**,為每個請求提供一個新的 `Session`。這可確保每個請求只使用單一的 session。🤓
 
 接著我們建立一個 `Annotated` 的依賴 `SessionDep`,讓後續使用這個依賴的程式碼更簡潔。
 
@@ -117,11 +117,11 @@ SQLModel 之後會提供包裝 Alembic 的遷移工具,但目前你可以直
 
 ### 建立 Hero { #create-a-hero }
 
-因為每個 SQLModel 模型同時也是一個 Pydantic 模型,你可以在「型別標註」中像使用 Pydantic 模型一樣使用它。
+因為每個 SQLModel 模型同時也是一個 Pydantic 模型,你可以在與 Pydantic 模型相同的**型別標註**中使用它。
 
-例如,如果你宣告一個參數型別為 `Hero`,它會從「JSON body」中讀取。
+例如,如果你宣告一個參數型別為 `Hero`,它會從 **JSON body** 中讀取。
 
-同樣地,你也可以將它宣告為函式的「回傳型別」,然後在自動產生的 API 文件 UI 中就會顯示其資料結構。
+同樣地,你也可以將它宣告為函式的**回傳型別**,然後在自動產生的 API 文件 UI 中就會顯示其資料結構。
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
 
@@ -129,19 +129,19 @@ SQLModel 之後會提供包裝 Alembic 的遷移工具,但目前你可以直
 
 ### 讀取多個 Hero { #read-heroes }
 
-我們可以用 `select()` 從資料庫「讀取」多個 `Hero`。可以加入 `limit` 與 `offset` 來分頁。
+我們可以用 `select()` 從資料庫**讀取**多個 `Hero`。可以加入 `limit` 與 `offset` 來分頁。
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
 
 ### 讀取單一 Hero { #read-one-hero }
 
-我們可以「讀取」單一的 `Hero`。
+我們可以**讀取**單一的 `Hero`。
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
 
 ### 刪除 Hero { #delete-a-hero }
 
-我們也可以「刪除」一個 `Hero`。
+我們也可以**刪除**一個 `Hero`。
 
 {* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
 
@@ -159,7 +159,7 @@ $ fastapi dev
 
 </div>
 
-然後前往 `/docs` 的 UI,你會看到 FastAPI 使用這些模型來「文件化」API,也會用它們來「序列化」與「驗證」資料。
+然後前往 `/docs` 的 UI,你會看到 **FastAPI** 使用這些**模型**來**文件化** API,也會用它們來**序列化**與**驗證**資料。
 
 <div class="screenshot">
 <img src="/img/tutorial/sql-databases/image01.png">
@@ -167,27 +167,27 @@ $ fastapi dev
 
 ## 用多個模型更新應用 { #update-the-app-with-multiple-models }
 
-現在我們稍微「重構」一下這個應用,以提升「安全性」與「彈性」
+現在我們稍微**重構**一下這個應用,以提升**安全性**與**彈性**
 
 如果你檢查前一版的應用,在 UI 中你會看到,到目前為止它讓用戶端自己決定要建立的 `Hero` 的 `id`。😱
 
-我們不該允許這樣,因為他們可能會覆蓋資料庫中我們已分配的 `id`。決定 `id` 應該由「後端」或「資料庫」來做,「不是用戶端」
+我們不該允許這樣,因為他們可能會覆蓋資料庫中我們已分配的 `id`。決定 `id` 應該由**後端**或**資料庫**來做,**不是用戶端**
 
-另外,我們為 hero 建立了 `secret_name`,但目前我們在各處都把它回傳出去,這一點都不「保密」... 😅
+另外,我們為 hero 建立了 `secret_name`,但目前我們在各處都把它回傳出去,這一點都不**保密**... 😅
 
-我們會透過加入一些「額外模型」來修正這些問題。這正是 SQLModel 大放異彩的地方。✨
+我們會透過加入一些**額外模型**來修正這些問題。這正是 SQLModel 大放異彩的地方。✨
 
 ### 建立多個模型 { #create-multiple-models }
 
-在 SQLModel 中,任何設了 `table=True` 的模型類別都是「資料表模型」
+在 **SQLModel** 中,任何設了 `table=True` 的模型類別都是**資料表模型**
 
-而沒有設 `table=True` 的模型類別就是「資料模型」,這些其實就是 Pydantic 模型(只有一點小增強)。🤓
+而沒有設 `table=True` 的模型類別就是**資料模型**,這些其實就是 Pydantic 模型(只有一點小增強)。🤓
 
-使用 SQLModel,我們可以利用「繼承」來「避免重複」在各種情況下一再宣告所有欄位。
+使用 SQLModel,我們可以利用**繼承**來**避免重複**在各種情況下一再宣告所有欄位。
 
 #### `HeroBase` - 基底類別 { #herobase-the-base-class }
 
-先從 `HeroBase` 模型開始,它包含所有模型「共享」的欄位:
+先從 `HeroBase` 模型開始,它包含所有模型**共享**的欄位:
 
 * `name`
 * `age`
@@ -196,12 +196,12 @@ $ fastapi dev
 
 #### `Hero` - 資料表模型 { #hero-the-table-model }
 
-接著建立 `Hero`,也就是實際的「資料表模型」,它包含不一定會出現在其他模型中的「額外欄位」
+接著建立 `Hero`,也就是實際的*資料表模型*,它包含不一定會出現在其他模型中的**額外欄位**
 
 * `id`
 * `secret_name`
 
-因為 `Hero` 繼承自 `HeroBase`,它「也」擁有 `HeroBase` 中宣告的「欄位」,因此 `Hero` 的完整欄位為:
+因為 `Hero` 繼承自 `HeroBase`,它**也**擁有 `HeroBase` 中宣告的**欄位**,因此 `Hero` 的完整欄位為:
 
 * `id`
 * `name`
@@ -212,19 +212,19 @@ $ fastapi dev
 
 #### `HeroPublic` - 公開的資料模型 { #heropublic-the-public-data-model }
 
-接下來建立 `HeroPublic` 模型,它是要「回傳」給 API 用戶端的模型。
+接下來建立 `HeroPublic` 模型,它是要**回傳**給 API 用戶端的模型。
 
 它擁有與 `HeroBase` 相同的欄位,因此不會包含 `secret_name`。
 
 終於,我們英雄的真實身分受保護了!🥷
 
-它也重新宣告了 `id: int`。這麼做是與 API 用戶端訂立一個「契約」,讓他們可以確定 `id` 一定存在而且是 `int`(不會是 `None`)。
+它也重新宣告了 `id: int`。這麼做是與 API 用戶端訂立一個**契約**,讓他們可以確定 `id` 一定存在而且是 `int`(不會是 `None`)。
 
 /// tip | 提示
 
 讓回傳模型保證某個值一定存在、而且一定是 `int`(不是 `None`),對 API 用戶端非常有幫助。他們在有這個確信下可以寫出更簡單的程式碼。
 
-此外,透過「自動產生的客戶端」也會有更簡潔的介面,讓要使用你 API 的開發者能有更好的開發體驗。😎
+此外,透過**自動產生的客戶端**也會有更簡潔的介面,讓要使用你 API 的開發者能有更好的開發體驗。😎
 
 ///
 
@@ -238,17 +238,17 @@ $ fastapi dev
 
 #### `HeroCreate` - 用於建立 Hero 的資料模型 { #herocreate-the-data-model-to-create-a-hero }
 
-現在我們建立 `HeroCreate` 模型,這是用來「驗證」用戶端送來資料的模型。
+現在我們建立 `HeroCreate` 模型,這是用來**驗證**用戶端送來資料的模型。
 
 它具有與 `HeroBase` 相同的欄位,並且還有 `secret_name`。
 
-接下來,當用戶端「建立新 hero」時,他們會送上 `secret_name`,它會被儲存在資料庫中,但這些祕密名稱不會在 API 中回傳給用戶端。
+接下來,當用戶端**建立新 hero** 時,他們會送上 `secret_name`,它會被儲存在資料庫中,但這些祕密名稱不會在 API 中回傳給用戶端。
 
 /// tip | 提示
 
-這也就是你處理「密碼」的方式。接收它們,但不要在 API 中回傳。
+這也就是你處理**密碼**的方式。接收它們,但不要在 API 中回傳。
 
-你也應該在儲存前先對密碼做「雜湊」,「永遠不要以明文儲存」
+你也應該在儲存前先對密碼做**雜湊**,**永遠不要以明文儲存**
 
 ///
 
@@ -262,11 +262,11 @@ $ fastapi dev
 
 #### `HeroUpdate` - 用於更新 Hero 的資料模型 { #heroupdate-the-data-model-to-update-a-hero }
 
-在前一版的應用中,我們沒有「更新 hero」的方式,但現在有了「多個模型」,我們就能做到。🎉
+在前一版的應用中,我們沒有**更新 hero** 的方式,但現在有了**多個模型**,我們就能做到。🎉
 
-`HeroUpdate` 這個資料模型有點特別,它包含「建立新 hero 所需的所有欄位」,但所有欄位都是「可選的」(都有預設值)。這樣在更新時,你只需要送出想要更新的欄位即可。
+`HeroUpdate` 這個*資料模型*有點特別,它包含**建立新 hero 所需的所有欄位**,但所有欄位都是**可選的**(都有預設值)。這樣在更新時,你只需要送出想要更新的欄位即可。
 
-因為所有欄位的「型別其實都改變了」(型別現在包含 `None`,而且預設值為 `None`),我們需要「重新宣告」它們。
+因為所有**欄位其實都改變了**(型別現在包含 `None`,而且預設值為 `None`),我們需要**重新宣告**它們。
 
 其實不一定要繼承 `HeroBase`,因為我們會重新宣告所有欄位。我這裡保留繼承只是為了一致性,並非必要。這主要是個人偏好的問題。🤷
 
@@ -280,43 +280,43 @@ $ fastapi dev
 
 ### 用 `HeroCreate` 建立並回傳 `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
 
-現在我們有了「多個模型」,可以更新應用中使用它們的部分。
+現在我們有了**多個模型**,可以更新應用中使用它們的部分。
 
-我們在請求中接收 `HeroCreate`(資料模型),並由它建立一個 `Hero`(資料表模型)
+我們在請求中接收 `HeroCreate` *資料模型*,並由它建立一個 `Hero` *資料表模型*
 
-這個新的資料表模型 `Hero` 會有用戶端傳來的欄位,並且會由資料庫產生一個 `id`。
+這個新的*資料表模型* `Hero` 會有用戶端傳來的欄位,並且會由資料庫產生一個 `id`。
 
-然後我們直接從函式回傳這個資料表模型 `Hero`。但因為我們用 `HeroPublic` 當作 `response_model`,FastAPI 會用 `HeroPublic` 來驗證與序列化資料。
+然後我們直接從函式回傳這個*資料表模型* `Hero`。但因為我們用 `HeroPublic` *資料模型*當作 `response_model`,**FastAPI** 會用 `HeroPublic` 來驗證與序列化資料。
 
 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
 
 /// tip | 提示
 
-現在我們用 `response_model=HeroPublic`,而不是用回傳型別標註 `-> HeroPublic`,因為我們實際回傳的值其實「不是」`HeroPublic`。
+現在我們用 `response_model=HeroPublic`,而不是用**回傳型別標註** `-> HeroPublic`,因為我們實際回傳的值其實*不是* `HeroPublic`。
 
 如果我們宣告 `-> HeroPublic`,你的編輯器與 linter 會(理所當然地)抱怨你回傳的是 `Hero` 而不是 `HeroPublic`。
 
-在 `response_model` 中宣告,就是要讓 FastAPI 去做它該做的事,而不影響型別標註,以及你的編輯器與其他工具提供的協助。
+在 `response_model` 中宣告,就是要讓 **FastAPI** 去做它該做的事,而不影響型別標註,以及你的編輯器與其他工具提供的協助。
 
 ///
 
 ### 使用 `HeroPublic` 讀取多個 Hero { #read-heroes-with-heropublic }
 
-我們可以像先前一樣「讀取」多個 `Hero`。同樣地,我們使用 `response_model=list[HeroPublic]` 來確保資料被正確驗證與序列化。
+我們可以像先前一樣**讀取**多個 `Hero`。同樣地,我們使用 `response_model=list[HeroPublic]` 來確保資料被正確驗證與序列化。
 
 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
 
 ### 使用 `HeroPublic` 讀取單一 Hero { #read-one-hero-with-heropublic }
 
-我們可以「讀取」單一 hero:
+我們可以**讀取**單一 hero:
 
 {* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
 
 ### 使用 `HeroUpdate` 更新 Hero { #update-a-hero-with-heroupdate }
 
-我們可以「更新 hero」。為此我們使用 HTTP 的 `PATCH` 操作。
+我們可以**更新 hero**。為此我們使用 HTTP 的 `PATCH` 操作。
 
-在程式碼中,我們會取得一個只包含用戶端有傳送的資料的 `dict`,不包含只是因為有預設值而存在的欄位。為了達成這點,我們使用 `exclude_unset=True`。這是關鍵。🪄
+在程式碼中,我們會取得一個只包含用戶端有傳送的資料的 `dict`,**只包含用戶端傳送的資料**,不包含只是因為有預設值而存在的欄位。為了達成這點,我們使用 `exclude_unset=True`。這是關鍵。🪄
 
 然後我們使用 `hero_db.sqlmodel_update(hero_data)` 以 `hero_data` 的資料更新 `hero_db`。
 
@@ -324,7 +324,7 @@ $ fastapi dev
 
 ### 再次刪除 Hero { #delete-a-hero-again }
 
-「刪除」 hero 基本上維持不變。
+**刪除** hero 基本上維持不變。
 
 我們不會為了重構而重構一切。😅
 
@@ -352,6 +352,6 @@ $ fastapi dev
 
 ## 總結 { #recap }
 
-你可以使用 [SQLModel](https://sqlmodel.tiangolo.com/) 與 SQL 資料庫互動,並用「資料模型」與「資料表模型」讓程式碼更簡潔。
+你可以使用 [**SQLModel**](https://sqlmodel.tiangolo.com/) 與 SQL 資料庫互動,並用*資料模型*與*資料表模型*讓程式碼更簡潔。
 
-你可以在 SQLModel 文件學到更多內容,這裡還有一份更長的 [使用 SQLModel 與 FastAPI 的教學](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。🚀
+你可以在 **SQLModel** 文件學到更多內容,這裡還有一份更長的 [使用 SQLModel 與 **FastAPI** 的教學](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。🚀
index 1b9e92a1c9eb6f0abc014aed713dfe971044c576..0d6369eef71f9c81813f9314dc923bb34a051a39 100644 (file)
@@ -2,6 +2,14 @@
 
 你可以使用 `StaticFiles` 從某個目錄自動提供靜態檔案。
 
+/// tip
+
+如果你需要託管前端,請改用 `app.frontend()`,請在 [前端](frontend.md) 閱讀相關內容。
+
+`app.frontend()` 底層使用 `StaticFiles`,並為前端提供幾項額外優勢,例如處理客戶端路由。
+
+///
+
 ## 使用 `StaticFiles` { #use-staticfiles }
 
 - 匯入 `StaticFiles`。
index ab9dac93cc7d692bc0557c60d3f8132e15f867cd..09f6c0ec7a3d5c74889d63f09416bc693150d0e0 100644 (file)
@@ -113,13 +113,13 @@ $ pip install httpx
 │   └── test_main.py
 ```
 
-假設現在你的 **FastAPI** 應用所在的 `main.py` 有一些其他的路徑操作(path operations)
+假設現在你的 **FastAPI** 應用所在的 `main.py` 有一些其他的 **路徑操作**
 
 它有一個可能回傳錯誤的 `GET` 操作。
 
 它有一個可能回傳多種錯誤的 `POST` 操作。
 
-兩個路徑操作都需要一個 `X-Token` 標頭(header)。
+兩個 *路徑操作* 都需要一個 `X-Token` 標頭(header)。
 
 {* ../../docs_src/app_testing/app_b_an_py310/main.py *}
 
@@ -136,11 +136,11 @@ $ pip install httpx
 
 例如:
 
-* 要傳遞路徑或查詢參數,直接把它加在 URL 上。
+* 要傳遞 *path* 或 *query* 參數,直接把它加在 URL 上。
 * 要傳遞 JSON 本文,將 Python 物件(例如 `dict`)傳給 `json` 參數。
-* 如果需要送出表單資料(Form Data)而不是 JSON,改用 `data` 參數。
-* 要傳遞標頭(headers),在 `headers` 參數中放一個 `dict`。
-* 對於 Cookie(cookies),在 `cookies` 參數中放一個 `dict`。
+* 如果需要送出 *Form Data* 而不是 JSON,改用 `data` 參數。
+* 要傳遞 *headers*,在 `headers` 參數中放一個 `dict`。
+* 對於 *cookies*,在 `cookies` 參數中放一個 `dict`。
 
 關於如何把資料傳給後端(使用 `httpx` 或 `TestClient`),更多資訊請參考 [HTTPX 文件](https://www.python-httpx.org)。
 
index a4d649c13346f7f9f69c30fcb332f10682ae0754..5503634133771098857fb6c902490edc0fd2224d 100644 (file)
@@ -73,7 +73,7 @@ $ python -m venv .venv
 
 </div>
 
-/// details | 上述令的含義
+/// details | 上述令的含義
 
 * `python`: 使用名為 `python` 的程式
 * `-m`: 以腳本的方式呼叫一個模組,我們將告訴它接下來使用哪個模組
@@ -106,7 +106,7 @@ $ uv venv
 
 ////
 
-這個令會在一個名為 `.venv` 的目錄中建立一個新的虛擬環境。
+這個令會在一個名為 `.venv` 的目錄中建立一個新的虛擬環境。
 
 /// details | `.venv`,或是其他名稱
 
@@ -164,7 +164,7 @@ $ source .venv/Scripts/activate
 
 /// tip
 
-每次你在這個環境中安裝一個**新的套件**時,都需要**重新啟動**這個環境。
+每次你在這個環境中安裝一個**新的套件**時,都需要**再次啟用**這個環境。
 
 這麼做確保了當你使用一個由這個套件安裝的**終端(<abbr title="command line interface - 命令列介面">CLI</abbr>)程式**時,你使用的是你的虛擬環境中的程式,而不是全域安裝、可能版本不同的程式。
 
@@ -242,7 +242,7 @@ $ python -m pip install --upgrade pip
 
 </div>
 
-/// tip | 注意
+/// tip
 
 有時你在嘗試升級 pip 時,可能會遇到 **`No module named pip`** 的錯誤。
 
@@ -544,7 +544,7 @@ Python 套件在推出**新版本**時通常會儘量**避免破壞性更改**
 
 現在,想像一下如果有**許多**其他**套件**,它們都是你的**專案所依賴的**。這樣是非常難以管理的。你可能會發現有些專案使用了一些**不相容的套件版本**,而無法得知為什麼某些程式無法正常運作。
 
-此外,取決於你的操作系統(例如 Linux、Windows、macOS),它可能已經預先安裝了 Python。在這種情況下,它可能已經有一些系統所需的套件和特定版本。如果你在全域 Python 環境中安裝套件,可能會**破壞**某些隨作業系統一起安裝的程式。
+此外,取決於你的作業系統(例如 Linux、Windows、macOS),它可能已經預先安裝了 Python。在這種情況下,它可能已經有一些系統所需的套件和特定版本。如果你在全域 Python 環境中安裝套件,可能會**破壞**某些隨作業系統一起安裝的程式。
 
 ## 套件安裝在哪裡 { #where-are-packages-installed }