Sync fastapi docs from b5ca1324 on 2025-12-07
Issue Manager / issue-manager (push) Has been cancelled
Build Docs / changes (push) Has been cancelled
Build Docs / langs (push) Has been cancelled
Build Docs / build-docs (push) Has been cancelled
Build Docs / docs-all-green (push) Has been cancelled
Conflict detector / main (push) Has been cancelled
Test Redistribute / test-redistribute (fastapi) (push) Has been cancelled
Test Redistribute / test-redistribute (fastapi-slim) (push) Has been cancelled
Test Redistribute / test-redistribute-alls-green (push) Has been cancelled
Test / lint (push) Has been cancelled
Test / test (pydantic-v1, 3.10) (push) Has been cancelled
Test / test (pydantic-v1, 3.11) (push) Has been cancelled
Test / test (pydantic-v1, 3.13) (push) Has been cancelled
Test / test (pydantic-v1, 3.8) (push) Has been cancelled
Test / test (pydantic-v1, 3.9) (push) Has been cancelled
Test / test (pydantic-v2, 3.10) (push) Has been cancelled
Test / test (pydantic-v2, 3.11) (push) Has been cancelled
Test / test (pydantic-v2, 3.12) (push) Has been cancelled
Test / test (pydantic-v2, 3.13) (push) Has been cancelled
Test / test (pydantic-v2, 3.14) (push) Has been cancelled
Test / test (pydantic-v2, 3.8) (push) Has been cancelled
Test / test (pydantic-v2, 3.9) (push) Has been cancelled
Test / coverage-combine (push) Has been cancelled
Test / check (push) Has been cancelled
Label Approved / label-approved (push) Has been cancelled
FastAPI People Contributors / job (push) Has been cancelled
FastAPI People Sponsors / job (push) Has been cancelled
Update Topic Repos / topic-repos (push) Has been cancelled
FastAPI People / job (push) Has been cancelled
Test / test (pydantic-v1, 3.12) (push) Has been cancelled

This commit is contained in:
The Scheduler
2025-12-07 21:35:20 +00:00
commit a42b1ff04e
2600 changed files with 301870 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# 關於 FastAPI
關於 FastAPI、其設計、靈感來源等更多資訊。 🤓
+442
View File
@@ -0,0 +1,442 @@
# 並行與 async / await
有關*路徑操作函式*的 `async def` 語法的細節與非同步 (asynchronous) 程式碼、並行 (concurrency) 與平行 (parallelism) 的一些背景知識。
## 趕時間嗎?
<abbr title="too long; didn't read(文長慎入)"><strong>TL;DR:</strong></abbr>
如果你正在使用要求你以 `await` 語法呼叫的第三方函式庫,例如:
```Python
results = await some_library()
```
然後,使用 `async def` 宣告你的*路徑操作函式*
```Python hl_lines="2"
@app.get('/')
async def read_results():
results = await some_library()
return results
```
/// note | 注意
你只能在 `async def` 建立的函式內使用 `await`。
///
---
如果你使用的是第三方函式庫並且它需要與某些外部資源(例如資料庫、API、檔案系統等)進行通訊,但不支援 `await`(目前大多數資料庫函式庫都是這樣),在這種情況下,你可以像平常一樣使用 `def` 宣告*路徑操作函式*,如下所示:
```Python hl_lines="2"
@app.get('/')
def results():
results = some_library()
return results
```
---
如果你的應用程式不需要與外部資源進行任何通訊並等待其回應,請使用 `async def`。
---
如果你不確定該用哪個,直接用 `def` 就好。
---
**注意**:你可以在*路徑操作函式*中混合使用 `def` 和 `async def` ,並使用最適合你需求的方式來定義每個函式。FastAPI 會幫你做正確的處理。
無論如何,在上述哪種情況下,FastAPI 仍將以非同步方式運行,並且速度非常快。
但透過遵循上述步驟,它將能進行一些效能最佳化。
## 技術細節
現代版本的 Python 支援使用 **「協程」** 的 **`async` 和 `await`** 語法來寫 **「非同步程式碼」**。
接下來我們逐一介紹:
* **非同步程式碼**
* **`async` 和 `await`**
* **協程**
## 非同步程式碼
非同步程式碼僅意味著程式語言 💬 有辦法告訴電腦/程式 🤖 在程式碼中的某個點,它 🤖 需要等待某些事情完成。讓我們假設這些事情被稱為「慢速檔案」📝。
因此,在等待「慢速檔案」📝 完成的這段時間,電腦可以去處理一些其他工作。
接著程式 🤖 會在有空檔時回來查看是否有等待的工作已經完成,並執行必要的後續操作。
接下來,它 🤖 完成第一個工作(例如我們的「慢速檔案」📝)並繼續執行相關的所有操作。
這個「等待其他事情」通常指的是一些相對較慢的(與處理器和 RAM 記憶體的速度相比)的 <abbr title="Input and Output">I/O</abbr> 操作,比如說:
* 透過網路傳送來自用戶端的資料
* 從網路接收來自用戶端的資料
* 從磁碟讀取檔案內容
* 將內容寫入磁碟
* 遠端 API 操作
* 資料庫操作
* 資料庫查詢
* 等等
由於大部分的執行時間都消耗在等待 <abbr title="輸入與輸出">I/O</abbr> 操作上,因此這些操作被稱為 "I/O 密集型" 操作。
之所以稱為「非同步」,是因為電腦/程式不需要與那些耗時的任務「同步」,等待任務完成的精確時間,然後才能取得結果並繼續工作。
相反地,非同步系統在任務完成後,可以讓任務稍微等一下(幾微秒),等待電腦/程式完成手頭上的其他工作,然後再回來取得結果繼續進行。
相對於「非同步」(asynchronous),「同步」(synchronous)也常被稱作「順序性」(sequential),因為電腦/程式會依序執行所有步驟,即便這些步驟涉及等待,才會切換到其他任務。
### 並行與漢堡
上述非同步程式碼的概念有時也被稱為「並行」,它不同於「平行」。
並行和平行都與 "不同的事情或多或少同時發生" 有關。
但並行和平行之間的細節是完全不同的。
為了理解差異,請想像以下有關漢堡的故事:
### 並行漢堡
你和你的戀人去速食店,排隊等候時,收銀員正在幫排在你前面的人點餐。😍
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
輪到你了,你給你與你的戀人點了兩個豪華漢堡。🍔🍔
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
收銀員通知廚房準備你的漢堡(儘管他們還在為前面其他顧客準備食物)。
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
之後你完成付款。💸
收銀員給你一個號碼牌。
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
在等待漢堡的同時,你可以與戀人選一張桌子,然後坐下來聊很長一段時間(因為漢堡十分豪華,準備特別費工。)
這段時間,你還能欣賞你的戀人有多麼的可愛、聰明與迷人。✨😍✨
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
當你和戀人邊聊天邊等待時,你會不時地查看櫃檯上的顯示的號碼,確認是否已經輪到你了。
然後在某個時刻,終於輪到你了。你走到櫃檯,拿了漢堡,然後回到桌子上。
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
你和戀人享用這頓大餐,整個過程十分開心✨
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
/// info
漂亮的插畫來自 <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
///
---
想像你是故事中的電腦或程式 🤖。
當你排隊時,你在放空😴,等待輪到你,沒有做任何「生產性」的事情。但這沒關係,因為收銀員只是接單(而不是準備食物),所以排隊速度很快。
然後,當輪到你時,你開始做真正「有生產力」的工作,處理菜單,決定你想要什麼,替戀人選擇餐點,付款,確認你給了正確的帳單或信用卡,檢查你是否被正確收費,確認訂單中的項目是否正確等等。
但是,即使你還沒有拿到漢堡,你與收銀員的工作已經「暫停」了 ⏸,因為你必須等待 🕙 漢堡準備好。
但當你離開櫃檯,坐到桌子旁,拿著屬於你的號碼等待時,你可以把注意力 🔀 轉移到戀人身上,並開始「工作」⏯ 🤓——也就是和戀人調情 😍。這時你又開始做一些非常「有生產力」的事情。
接著,收銀員 💁 將你的號碼顯示在櫃檯螢幕上,並告訴你「漢堡已經做好了」。但你不會瘋狂地立刻跳起來,因為顯示的號碼變成了你的。你知道沒有人會搶走你的漢堡,因為你有自己的號碼,他們也有他們的號碼。
所以你會等戀人講完故事(完成當前的工作 ⏯/正在進行的任務 🤓),然後微笑著溫柔地說你要去拿漢堡了 ⏸。
然後你走向櫃檯 🔀,回到已經完成的最初任務 ⏯,拿起漢堡,說聲謝謝,並帶回桌上。這就結束了與櫃檯的互動步驟/任務 ⏹,接下來會產生一個新的任務,「吃漢堡」 🔀 ⏯,而先前的「拿漢堡」任務已經完成了 ⏹。
### 平行漢堡
現在,讓我們來想像這裡不是「並行漢堡」,而是「平行漢堡」。
你和戀人一起去吃平行的速食餐。
你們站在隊伍中,前面有幾位(假設有 8 位)既是收銀員又是廚師的員工,他們同時接單並準備餐點。
所有排在你前面的人都在等著他們的漢堡準備好後才會離開櫃檯,因為每位收銀員在接完單後,馬上會去準備漢堡,然後才回來處理下一個訂單。
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
終於輪到你了,你為你和你的戀人點了兩個非常豪華的漢堡。
你付款了 💸。
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
收銀員走進廚房準備食物。
你站在櫃檯前等待 🕙,以免其他人先拿走你的漢堡,因為這裡沒有號碼牌系統。
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
由於你和戀人都忙著不讓別人搶走你的漢堡,等漢堡準備好時,你根本無法專心和戀人互動。😞
這是「同步」(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">
你拿著漢堡,和你的戀人回到餐桌。
你們僅僅是吃完漢堡,然後就結束了。⏹
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
整個過程中沒有太多的談情說愛,因為大部分時間 🕙 都花在櫃檯前等待。😞
/// info
漂亮的插畫來自 <a href="https://www.instagram.com/ketrinadrawsalot" class="external-link" target="_blank">Ketrina Thompson</a>. 🎨
///
---
在這個平行漢堡的情境下,你是一個程式 🤖 且有兩個處理器(你和戀人),兩者都在等待 🕙 並專注於等待櫃檯上的餐點 🕙,等待的時間非常長。
這家速食店有 8 個處理器(收銀員/廚師)。而並行漢堡店可能只有 2 個處理器(一位收銀員和一位廚師)。
儘管如此,最終的體驗並不是最理想的。😞
---
這是與漢堡類似的故事。🍔
一個更「現實」的例子,想像一間銀行。
直到最近,大多數銀行都有多位出納員 👨‍💼👨‍💼👨‍💼👨‍💼,以及一條長長的隊伍 🕙🕙🕙🕙🕙🕙🕙🕙。
所有的出納員都在一個接一個地滿足每位客戶的所有需求 👨‍💼⏯。
你必須長時間排隊 🕙,不然就會失去機會。
所以,你不會想帶你的戀人 😍 一起去銀行辦事 🏦。
### 漢堡結論
在「和戀人一起吃速食漢堡」的這個場景中,由於有大量的等待 🕙,使用並行系統 ⏸🔀⏯ 更有意義。
這也是大多數 Web 應用的情況。
許多用戶正在使用你的應用程式,而你的伺服器則在等待 🕙 這些用戶不那麼穩定的網路來傳送請求。
接著,再次等待 🕙 回應。
這種「等待」 🕙 通常以微秒來衡量,但累加起來,最終還是花費了很多等待時間。
這就是為什麼對於 Web API 來說,使用非同步程式碼 ⏸🔀⏯ 是非常有意義的。
這種類型的非同步性正是 NodeJS 成功的原因(儘管 NodeJS 不是平行的),這也是 Go 語言作為程式語言的一個強大優勢。
這與 **FastAPI** 所能提供的性能水平相同。
你可以同時利用並行性和平行性,進一步提升效能,這比大多數已測試的 NodeJS 框架都更快,並且與 Go 語言相當,而 Go 是一種更接近 C 的編譯語言(<a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">感謝 Starlette</a>)。
### 並行比平行更好嗎?
不是的!這不是故事的本意。
並行與平行不同。並行在某些 **特定** 的需要大量等待的情境下表現更好。正因如此,並行在 Web 應用程式開發中通常比平行更有優勢。但並不是所有情境都如此。
因此,為了平衡報導,想像下面這個短故事
> 你需要打掃一間又大又髒的房子。
*是的,這就是全部的故事。*
---
這裡沒有任何需要等待 🕙 的地方,只需要在房子的多個地方進行大量的工作。
你可以像漢堡的例子那樣輪流進行,先打掃客廳,再打掃廚房,但由於你不需要等待 🕙 任何事情,只需要持續地打掃,輪流並不會影響任何結果。
無論輪流執行與否(並行),你都需要相同的工時完成任務,同時需要執行相同工作量。
但是,在這種情境下,如果你可以邀請8位前收銀員/廚師(現在是清潔工)來幫忙,每個人(加上你)負責房子的某個區域,這樣你就可以 **平行** 地更快完成工作。
在這個場景中,每個清潔工(包括你)都是一個處理器,完成工作的一部分。
由於大多數的執行時間都花在實際的工作上(而不是等待),而電腦中的工作由 <abbr title="Central Processing Unit">CPU</abbr> 完成,因此這些問題被稱為「CPU 密集型」。
---
常見的 CPU 密集型操作範例包括那些需要進行複雜數學計算的任務。
例如:
* **音訊**或**圖像處理**
* **電腦視覺**:一張圖片由數百萬個像素組成,每個像素有 3 個值/顏色,處理這些像素通常需要同時進行大量計算;
* **機器學習**: 通常需要大量的「矩陣」和「向量」運算。想像一個包含數字的巨大電子表格,並所有的數字同時相乘;
* **深度學習**: 這是機器學習的子領域,同樣適用。只不過這不僅僅是一張數字表格,而是大量的數據集合,並且在很多情況下,你會使用特殊的處理器來構建或使用這些模型。
### 並行 + 平行: Web + 機器學習
使用 **FastAPI**,你可以利用並行的優勢,這在 Web 開發中非常常見(這也是 NodeJS 的最大吸引力)。
但你也可以利用平行與多行程 (multiprocessing)(讓多個行程同時運行) 的優勢來處理機器學習系統中的 **CPU 密集型**工作。
這一點,再加上 Python 是 **資料科學**、機器學習,尤其是深度學習的主要語言,讓 **FastAPI** 成為資料科學/機器學習 Web API 和應用程式(以及許多其他應用程式)的絕佳選擇。
想了解如何在生產環境中實現這種平行性,請參見 [部屬](deployment/index.md){.internal-link target=_blank}。
## `async` 和 `await`
現代 Python 版本提供一種非常直觀的方式定義非同步程式碼。這使得它看起來就像正常的「順序」程式碼,並在適當的時機「等待」。
當某個操作需要等待才能回傳結果,並且支援這些新的 Python 特性時,你可以像這樣編寫程式碼:
```Python
burgers = await get_burgers(2)
```
這裡的關鍵是 `await`。它告訴 Python 必須等待 ⏸ `get_burgers(2)` 完成它的工作 🕙, 然後將結果儲存在 `burgers` 中。如此,Python 就可以在此期間去處理其他事情 🔀 ⏯ (例如接收另一個請求)。
要讓 `await` 運作,它必須位於支持非同步功能的函式內。為此,只需使用 `async def` 宣告函式:
```Python hl_lines="1"
async def get_burgers(number: int):
# Do some asynchronous stuff to create the burgers
return burgers
```
...而不是 `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 Python 知道在該函式內需要注意 `await`,並且它可以「暫停」 ⏸ 執行該函式,然後執行其他任務 🔀 後回來。
當你想要呼叫 `async def` 函式時,必須使用「await」。因此,這樣寫將無法運行:
```Python
# This won't work, because get_burgers was defined with: async def
burgers = get_burgers(2)
```
---
如果你正在使用某個函式庫,它告訴你可以使用 `await` 呼叫它,那麼你需要用 `async def` 定義*路徑操作函式*,如:
```Python hl_lines="2-3"
@app.get('/burgers')
async def read_burgers():
burgers = await get_burgers(2)
return burgers
```
### 更多技術細節
你可能已經注意到,`await` 只能在 `async def` 定義的函式內使用。
但同時,使用 `async def` 定義的函式本身也必須被「等待」。所以,帶有 `async def` 函式只能在其他使用 `async def` 定義的函式內呼叫。
那麼,這就像「先有雞還是先有蛋」的問題,要如何呼叫第一個 `async` 函式呢?
如果你使用 FastAPI,無需擔心這個問題,因為「第一個」函式將是你的*路徑操作函式*,FastAPI 會知道如何正確處理這個問題。
但如果你想在沒有 FastAPI 的情況下使用 `async` / `await`,你也可以這樣做。
### 編寫自己的非同步程式碼
Starlette (和 **FastAPI** 是基於 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> 實作的,這使得它們與 Python 標準函式庫相容 <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a> 和 <a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>。
特別是,你可以直接使用 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> 來處理更複雜的並行使用案例,這些案例需要你在自己的程式碼中使用更高階的模式。
即使你不使用 **FastAPI**,你也可以使用 <a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a> 來撰寫自己的非同步應用程式,並獲得高相容性及一些好處(例如結構化並行)。
### 其他形式的非同步程式碼
使用 `async` 和 `await` 的風格在語言中相對較新。
但它使處理異步程式碼變得更加容易。
相同的語法(或幾乎相同的語法)最近也被包含在現代 JavaScript(無論是瀏覽器還是 NodeJS)中。
但在此之前,處理異步程式碼要更加複雜和困難。
在較舊的 Python 版本中,你可能會使用多執行緒或 <a href="https://www.gevent.org/" class="external-link" target="_blank">Gevent</a>。但這些程式碼要更難以理解、調試和思考。
在較舊的 NodeJS / 瀏覽器 JavaScript 中,你會使用「回呼」,這可能會導致“回呼地獄”。
## 協程
**協程** 只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西,可以啟動它,並且在某個時刻它會結束,但它也可能在內部暫停 ⏸,只要遇到 `await`。
這種使用 `async` 和 `await` 的非同步程式碼功能通常被概括為「協程」。這與 Go 語言的主要特性「Goroutines」相似。
## 結論
讓我們再次回顧之前的句子:
> 現代版本的 Python 支持使用 **"協程"** 的 **`async` 和 `await`** 語法來寫 **"非同步程式碼"**。
現在應該能明白其含意了。✨
這些就是驅動 FastAPI(通過 Starlette)運作的原理,也讓它擁有如此驚人的效能。
## 非常技術性的細節
/// warning
你大概可以跳過這段。
這裡是有關 FastAPI 內部技術細節。
如果你有相當多的技術背景(例如協程、執行緒、阻塞等),並且對 FastAPI 如何處理 `async def` 與常規 `def` 感到好奇,請繼續閱讀。
///
### 路徑操作函数
當你使用 `def` 而不是 `async def` 宣告*路徑操作函式*時,該函式會在外部的執行緒池(threadpool)中執行,然後等待結果,而不是直接呼叫(因為這樣會阻塞伺服器)。
如果你來自於其他不以這種方式運作的非同步框架,而且你習慣於使用普通的 `def` 定義僅進行簡單計算的*路徑操作函式*,目的是獲得微小的性能增益(大約 100 奈秒),請注意,在 FastAPI 中,效果會完全相反。在這些情況下,最好使用 `async def`除非你的*路徑操作函式*執行阻塞的 <abbr title="輸入/輸出:磁碟讀寫或網路通訊">I/O</abbr> 的程式碼。
不過,在這兩種情況下,**FastAPI** [仍然很快](index.md#_11){.internal-link target=_blank}至少與你之前的框架相當(或者更快)。
### 依賴項(Dependencies)
同樣適用於[依賴項](tutorial/dependencies/index.md){.internal-link target=_blank}。如果依賴項是一個標準的 `def` 函式,而不是 `async def`,那麼它在外部的執行緒池被運行。
### 子依賴項
你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (作為函式定義的參數),其中一些可能是用 `async def` 宣告,也可能是用 `def` 宣告。它們仍然可以正常運作,用 `def` 定義的那些將會在外部的執行緒中呼叫(來自執行緒池),而不是被「等待」。
### 其他輔助函式
你可以直接呼叫任何使用 `def` 或 `async def` 建立的其他輔助函式,FastAPI 不會影響你呼叫它們的方式。
這與 FastAPI 為你呼叫*路徑操作函式*和依賴項的邏輯有所不同。
如果你的輔助函式是用 `def` 宣告的,它將會被直接呼叫(按照你在程式碼中撰寫的方式),而不是在執行緒池中。如果該函式是用 `async def` 宣告,那麼你在呼叫時應該使用 `await` 等待其結果。
---
再一次強調,這些都是非常技術性的細節,如果你特地在尋找這些資訊,這些內容可能會對你有幫助。
否則,只需遵循上面提到的指引即可:<a href="#_1">趕時間嗎?</a>.
+34
View File
@@ -0,0 +1,34 @@
# 基準測試
由第三方機構 TechEmpower 的基準測試表明在 Uvicorn 下運行的 **FastAPI** 應用程式是 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">最快的 Python 可用框架之一</a>,僅次於 Starlette 和 Uvicorn 本身(於 FastAPI 內部使用)。
但是在查看基準得分和對比時,請注意以下幾點。
## 基準測試和速度
當你查看基準測試時,時常會見到幾個不同類型的工具被同時進行測試。
具體來說,是將 Uvicorn、Starlette 和 FastAPI 同時進行比較(以及許多其他工具)。
該工具解決的問題越簡單,其效能就越好。而且大多數基準測試不會測試該工具提供的附加功能。
層次結構如下:
* **Uvicorn**ASGI 伺服器
* **Starlette**:(使用 Uvicorn)一個網頁微框架
* **FastAPI**:(使用 Starlette)一個 API 微框架,具有用於建立 API 的多個附加功能、資料驗證等。
* **Uvicorn**
* 具有最佳效能,因為除了伺服器本身之外,它沒有太多額外的程式碼。
* 你不會直接在 Uvicorn 中編寫應用程式。這意味著你的程式碼必須或多或少地包含 Starlette(或 **FastAPI**)提供的所有程式碼。如果你這樣做,你的最終應用程式將具有與使用框架相同的開銷並最大限度地減少應用程式程式碼和錯誤。
* 如果你要比較 Uvicorn,請將其與 Daphne、Hypercorn、uWSGI 等應用程式伺服器進行比較。
* **Starlette**
* 繼 Uvicorn 之後的次佳表現。事實上,Starlette 使用 Uvicorn 來運行。因此它將可能只透過執行更多程式碼而變得比 Uvicorn「慢」。
* 但它為你提供了建立簡單網頁應用程式的工具,以及基於路徑的路由等。
* 如果你要比較 Starlette,請將其與 Sanic、Flask、Django 等網頁框架(或微框架)進行比較。
* **FastAPI**
* 就像 Starlette 使用 Uvicorn 並不能比它更快一樣, **FastAPI** 使用 Starlette,所以它不能比它更快。
* FastAPI 在 Starlette 基礎之上提供了更多功能。包含建構 API 時所需要的功能,例如資料驗證和序列化。FastAPI 可以幫助你自動產生 API 文件,(應用程式啟動時將會自動生成文件,所以不會增加應用程式運行時的開銷)。
* 如果你沒有使用 FastAPI 而是直接使用 Starlette(或其他工具,如 Sanic、Flask、Responder 等),你將必須自行實現所有資料驗證和序列化。因此,你的最終應用程式仍然具有與使用 FastAPI 建置相同的開銷。在許多情況下,這種資料驗證和序列化是應用程式中編寫最大量的程式碼。
* 因此透過使用 FastAPI,你可以節省開發時間、錯誤與程式碼數量,並且相比不使用 FastAPI 你很大可能會獲得相同或更好的效能(因為那樣你必須在程式碼中實現所有相同的功能)。
* 如果你要與 FastAPI 比較,請將其與能夠提供資料驗證、序列化和文件的網頁應用程式框架(或工具集)進行比較,例如 Flask-apispec、NestJS、Molten 等框架。
+13
View File
@@ -0,0 +1,13 @@
# 在雲端部署 FastAPI
你幾乎可以使用**任何雲端供應商**來部署你的 FastAPI 應用程式。
在大多數情況下,主要的雲端供應商都有部署 FastAPI 的指南。
## 雲端供應商 - 贊助商
一些雲端供應商 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨,這確保了 FastAPI 及其**生態系統**持續健康地**發展**。
這也展現了他們對 FastAPI 和其**社群**(包括你)的真正承諾,他們不僅希望為你提供**優質的服務**,還希望確保你擁有一個**良好且健康的框架**:FastAPI。🙇
你可能會想嘗試他們的服務,以下有他們的指南.
+21
View File
@@ -0,0 +1,21 @@
# 部署
部署 **FastAPI** 應用程式相對容易。
## 部署是什麼意思
**部署**應用程式指的是執行一系列必要的步驟,使其能夠**讓使用者存取和使用**
對於一個 **Web API**,部署通常涉及將其放置在**遠端伺服器**上,並使用性能優良且穩定的**伺服器程式**,確保使用者能夠高效、無中斷地存取應用程式,且不會遇到問題。
這與**開發**階段形成鮮明對比,在**開發**階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動伺服器等。
## 部署策略
根據你的使用場景和使用工具,有多種方法可以實現此目的。
你可以使用一些工具自行**部署伺服器**,你也可以使用能為你完成部分工作的**雲端服務**,或其他可能的選項。
我將向你展示在部署 **FastAPI** 應用程式時你可能應該記住的一些主要概念(儘管其中大部分適用於任何其他類型的 Web 應用程式)。
在接下來的部分中,你將看到更多需要記住的細節以及一些技巧。 ✨
+298
View File
@@ -0,0 +1,298 @@
# 環境變數
/// tip
如果你已經知道什麼是「環境變數」並且知道如何使用它們,你可以放心跳過這一部分。
///
環境變數(也稱為「**env var**」)是一個獨立於 Python 程式碼**之外**的變數,它存在於**作業系統**中,可以被你的 Python 程式碼(或其他程式)讀取。
環境變數對於處理應用程式**設定**(作為 Python **安裝**的一部分等方面)非常有用。
## 建立和使用環境變數
你在 **shell(終端機)**中就可以**建立**和使用環境變數,並不需要用到 Python:
//// tab | Linux, macOS, Windows Bash
<div class="termy">
```console
// 你可以使用以下指令建立一個名為 MY_NAME 的環境變數
$ export MY_NAME="Wade Wilson"
// 然後,你可以在其他程式中使用它,例如
$ echo "Hello $MY_NAME"
Hello Wade Wilson
```
</div>
////
//// tab | Windows PowerShell
<div class="termy">
```console
// 建立一個名為 MY_NAME 的環境變數
$ $Env:MY_NAME = "Wade Wilson"
// 在其他程式中使用它,例如
$ echo "Hello $Env:MY_NAME"
Hello Wade Wilson
```
</div>
////
## 在 Python 中讀取環境變數
你也可以在 Python **之外**的終端機中建立環境變數(或使用其他方法),然後在 Python 中**讀取**它們。
例如,你可以建立一個名為 `main.py` 的檔案,其中包含以下內容:
```Python hl_lines="3"
import os
name = os.getenv("MY_NAME", "World")
print(f"Hello {name} from Python")
```
/// tip
第二個參數是 <a href="https://docs.python.org/zh-tw/3.8/library/os.html#os.getenv" class="external-link" target="_blank">`os.getenv()`</a> 的預設回傳值。
如果沒有提供,預設值為 `None`,這裡我們提供 `"World"` 作為預設值。
///
然後你可以呼叫這個 Python 程式:
//// tab | Linux, macOS, Windows Bash
<div class="termy">
```console
// 這裡我們還沒有設定環境變數
$ python main.py
// 因為我們沒有設定環境變數,所以我們得到的是預設值
Hello World from Python
// 但是如果我們事先建立過一個環境變數
$ export MY_NAME="Wade Wilson"
// 然後再次呼叫程式
$ python main.py
// 現在就可以讀取到環境變數了
Hello Wade Wilson from Python
```
</div>
////
//// tab | Windows PowerShell
<div class="termy">
```console
// 這裡我們還沒有設定環境變數
$ python main.py
// 因為我們沒有設定環境變數,所以我們得到的是預設值
Hello World from Python
// 但是如果我們事先建立過一個環境變數
$ $Env:MY_NAME = "Wade Wilson"
// 然後再次呼叫程式
$ python main.py
// 現在就可以讀取到環境變數了
Hello Wade Wilson from Python
```
</div>
////
由於環境變數可以在程式碼之外設定,但可以被程式碼讀取,並且不必與其他檔案一起儲存(提交到 `git`),因此通常用於配置或**設定**。
你還可以為**特定的程式呼叫**建立特定的環境變數,該環境變數僅對該程式可用,且僅在其執行期間有效。
要實現這一點,只需在同一行內(程式本身之前)建立它:
<div class="termy">
```console
// 在這個程式呼叫的同一行中建立一個名為 MY_NAME 的環境變數
$ MY_NAME="Wade Wilson" python main.py
// 現在就可以讀取到環境變數了
Hello Wade Wilson from Python
// 在此之後這個環境變數將不再存在
$ python main.py
Hello World from Python
```
</div>
/// tip
你可以在 <a href="https://12factor.net/zh_cn/config" class="external-link" target="_blank">The Twelve-Factor App: 配置</a>中了解更多資訊。
///
## 型別和驗證
這些環境變數只能處理**文字字串**,因為它們是位於 Python 範疇之外的,必須與其他程式和作業系統的其餘部分相容(甚至與不同的作業系統相容,如 Linux、Windows、macOS)。
這意味著從環境變數中讀取的**任何值**在 Python 中都將是一個 `str`,任何型別轉換或驗證都必須在程式碼中完成。
你將在[進階使用者指南 - 設定和環境變數](./advanced/settings.md)中了解更多關於使用環境變數處理**應用程式設定**的資訊。
## `PATH` 環境變數
有一個**特殊的**環境變數稱為 **`PATH`**,作業系統(Linux、macOS、Windows)用它來查找要執行的程式。
`PATH` 變數的值是一個長字串,由 Linux 和 macOS 上的冒號 `:` 分隔的目錄組成,而在 Windows 上則是由分號 `;` 分隔的。
例如,`PATH` 環境變數可能如下所示:
//// tab | Linux, macOS
```plaintext
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
這意味著系統應該在以下目錄中查找程式:
- `/usr/local/bin`
- `/usr/bin`
- `/bin`
- `/usr/sbin`
- `/sbin`
////
//// tab | Windows
```plaintext
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
```
這意味著系統應該在以下目錄中查找程式:
- `C:\Program Files\Python312\Scripts`
- `C:\Program Files\Python312`
- `C:\Windows\System32`
////
當你在終端機中輸入一個**指令**時,作業系統會在 `PATH` 環境變數中列出的**每個目錄**中**查找**程式。
例如,當你在終端機中輸入 `python` 時,作業系統會在該列表中的**第一個目錄**中查找名為 `python` 的程式。
如果找到了,那麼作業系統將**使用它**;否則,作業系統會繼續在**其他目錄**中查找。
### 安裝 Python 並更新 `PATH`
安裝 Python 時,可能會詢問你是否要更新 `PATH` 環境變數。
//// tab | Linux, macOS
假設你安裝了 Python,並將其安裝在目錄 `/opt/custompython/bin` 中。
如果你選擇更新 `PATH` 環境變數,那麼安裝程式會將 `/opt/custompython/bin` 加入到 `PATH` 環境變數中。
它看起來大致會是這樣:
```plaintext
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
```
如此一來,當你在終端機輸入 `python` 時,系統會在 `/opt/custompython/bin` 中找到 Python 程式(最後一個目錄)並使用它。
////
//// tab | Windows
假設你安裝了 Python,並將其安裝在目錄 `C:\opt\custompython\bin` 中。
如果你選擇更新 `PATH` 環境變數(在 Python 安裝程式中,這個選項是名為 `Add Python x.xx to PATH` 的勾選框——譯者註),那麼安裝程式會將 `C:\opt\custompython\bin` 加入到 `PATH` 環境變數中。
```plaintext
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
```
如此一來,當你在終端機輸入 `python` 時,系統會在 `C:\opt\custompython\bin` 中找到 Python 程式(最後一個目錄)並使用它。
////
因此,如果你輸入:
<div class="termy">
```console
$ python
```
</div>
//// tab | Linux, macOS
系統會在 `/opt/custompython/bin` 中**找到** `python` 程式並執行它。
這大致等同於輸入以下指令:
<div class="termy">
```console
$ /opt/custompython/bin/python
```
</div>
////
//// tab | Windows
系統會在 `C:\opt\custompython\bin\python` 中**找到** `python` 程式並執行它。
這大致等同於輸入以下指令:
<div class="termy">
```console
$ C:\opt\custompython\bin\python
```
</div>
////
當學習[虛擬環境](virtual-environments.md)時,這些資訊將會很有用。
## 結論
透過這個教學,你應該對**環境變數**是什麼以及如何在 Python 中使用它們有了基本的了解。
你也可以在<a href="https://zh.wikipedia.org/wiki/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F" class="external-link" target="_blank">環境變數 - 維基百科</a> (<a href="https://en.wikipedia.org/wiki/Environment_variable" class="external-link" target="_blank">Wikipedia for Environment Variable</a>) 中了解更多關於它們的資訊。
在許多情況下,環境變數的用途和適用性可能不會立刻顯現。但是在開發過程中,它們會在許多不同的場景中出現,因此瞭解它們是非常必要的。
例如,你在接下來的[虛擬環境](virtual-environments.md)章節中將需要這些資訊。
+83
View File
@@ -0,0 +1,83 @@
# FastAPI CLI
**FastAPI CLI** 是一個命令列程式,能用來運行你的 FastAPI 應用程式、管理你的 FastAPI 專案等。
當你安裝 FastAPI(例如使用 `pip install "fastapi[standard]"`),它會包含一個叫做 `fastapi-cli` 的套件,這個套件提供了 `fastapi` 命令。
要運行你的 FastAPI 應用程式來進行開發,你可以使用 `fastapi dev` 命令:
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
│ │
│ 🐍 main.py │
│ │
╰──────────────────────╯
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
<font color="#3465A4">INFO </font> Found importable FastAPI app
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
│ │
│ <span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span> │
│ │
╰──────────────────────────╯
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
<span style="background-color:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ </font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"> │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: [&apos;/home/user/code/awesomeapp&apos;]
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
<font color="#4E9A06">INFO</font>: Waiting for application startup.
<font color="#4E9A06">INFO</font>: Application startup complete.
```
</div>
`fastapi` 命令列程式就是 **FastAPI CLI**
FastAPI CLI 接收你的 Python 程式路徑(例如 `main.py`),並自動檢測 FastAPI 實例(通常命名為 `app`),確定正確的引入模組流程,然後運行該應用程式。
在生產環境,你應該使用 `fastapi run` 命令。 🚀
**FastAPI CLI** 內部使用了 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>,這是一個高效能、適合生產環境的 ASGI 伺服器。 😎
## `fastapi dev`
執行 `fastapi dev` 會啟動開發模式。
預設情況下,**auto-reload** 功能是啟用的,當你對程式碼進行修改時,伺服器會自動重新載入。這會消耗較多資源,並且可能比禁用時更不穩定。因此,你應該只在開發環境中使用此功能。它也會在 IP 位址 `127.0.0.1` 上監聽,這是用於你的機器與自身通訊的 IP 位址(`localhost`)。
## `fastapi run`
執行 `fastapi run` 會以生產模式啟動 FastAPI。
預設情況下,**auto-reload** 功能是禁用的。它也會在 IP 位址 `0.0.0.0` 上監聽,表示會監聽所有可用的 IP 地址,這樣任何能與該機器通訊的人都可以公開存取它。這通常是你在生產環境中運行應用程式的方式,例如在容器中運行時。
在大多數情況下,你會(也應該)有一個「終止代理」來處理 HTTPS,這取決於你如何部署你的應用程式,你的服務供應商可能會為你做這件事,或者你需要自己設置它。
/// tip
你可以在[部署文件](deployment/index.md){.internal-link target=_blank}中了解更多相關資訊。
///
+207
View File
@@ -0,0 +1,207 @@
# 特性
## FastAPI 特性
**FastAPI** 提供了以下内容:
### 建立在開放標準的基礎上
* 使用 <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> 來建立 API,包含<abbr title="path,也被叫做: endpoints, routes">路徑</abbr><abbr title="也叫做 HTTP 方法,例如 POST, GET, PUT, DELETE">操作</abbr>、參數、請求內文、安全性等聲明。
* 使用 <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a>(因為 OpenAPI 本身就是基於 JSON Schema)自動生成資料模型文件。
* 經過縝密的研究後圍繞這些標準進行設計,而不是事後在已有系統上附加的一層功能。
* 這也讓我們在多種語言中可以使用自動**用戶端程式碼生成**。
### 能夠自動生成文件
FastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由於該框架基於 OpenAPI,因此有多種選擇,預設提供了兩種。
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a> 提供互動式探索,讓你可以直接從瀏覽器呼叫並測試你的 API 。
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a> 提供結構性的文件,讓你可以在瀏覽器中查看。
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### 現代 Python
這一切都基於標準的 **Python 型別**宣告(感謝 Pydantic)。無需學習新的語法,只需使用標準的現代 Python。
如果你需要 2 分鐘來學習如何使用 Python 型別(即使你不使用 FastAPI),可以看看這個簡短的教學:[Python 型別](python-types.md){.internal-link target=_blank}。
如果你寫帶有 Python 型別的程式碼:
```python
from datetime import date
from pydantic import BaseModel
# 宣告一個變數為 string
# 並在函式中獲得 editor support
def main(user_id: str):
return user_id
# 宣告一個 Pydantic model
class User(BaseModel):
id: int
name: str
joined: date
```
可以像這樣來使用:
```python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
second_user_data = {
"id": 4,
"name": "Mary",
"joined": "2018-11-30",
}
my_second_user: User = User(**second_user_data)
```
/// info
`**second_user_data` 意思是:
`second_user_data` 字典直接作為 key-value 引數傳遞,等同於:`User(id=4, name="Mary", joined="2018-11-30")`
///
### 多種編輯器支援
整個框架的設計是為了讓使用變得簡單且直觀,在開始開發之前,所有決策都在多個編輯器上進行了測試,以確保提供最佳的開發體驗。
在最近的 Python 開發者調查中,我們能看到<a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank"> 被使用最多的功能是 autocompletion</a>,此功能可以預測將要輸入文字,並自動補齊。
整個 **FastAPI** 框架就是基於這一點,任何地方都可以進行自動補齊。
你幾乎不需要經常來回看文件。
在這裡,你的編輯器可能會這樣幫助你:
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a> 中:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
* <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> 中:
![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)
你將能進行程式碼補齊,這是在之前你可能曾認為不可能的事。例如,請求 JSON body(可能是巢狀的)中的鍵 `price`
這樣比較不會輸錯鍵名,不用來回翻看文件,也不用來回滾動尋找你最後使用的 `username` 或者 `user_name`
### 簡潔
FastAPI 為你提供了**預設值**,讓你不必在初期進行繁瑣的配置,一切都可以自動運作。如果你有更具體的需求,則可以進行調整和自定義,
但在大多數情況下,你只需要直接使用預設值,就能順利完成 API 開發。
### 驗證
所有的驗證都由完善且強大的 **Pydantic** 處理。
* 驗證大部分(甚至所有?)的 Python **資料型別**,包括:
* JSON 物件 (`dict`)。
* JSON 陣列 (`list`) 定義項目型別。
* 字串 (`str`) 欄位,定義最小或最大長度。
* 數字 (`int`, `float`) 與其最大值和最小值等。
* 驗證外來的型別,比如:
* URL
* Email
* UUID
### 安全性及身份驗證
FastAPI 已經整合了安全性和身份驗證的功能,但不會強制與特定的資料庫或資料模型進行綁定。
OpenAPI 中定義的安全模式,包括:
* HTTP 基本認證。
* **OAuth2**(也使用 **JWT tokens**)。在 [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank} 查看教學。
* API 密鑰,在:
* 標頭(Header
* 查詢參數
* Cookies,等等。
加上来自 Starlette(包括 **session cookie**)的所有安全特性。
所有的這些都是可重複使用的工具和套件,可以輕鬆與你的系統、資料儲存(Data Stores)、關聯式資料庫(RDBMS)以及非關聯式資料庫(NoSQL)等等整合。
### 依賴注入(Dependency Injection
FastAPI 有一個使用簡單,但是非常強大的<abbr title='也叫做 "components", "resources", "services", "providers"'><strong>依賴注入</strong></abbr>系統。
* 依賴項甚至可以有自己的依賴,從而形成一個層級或**依賴圖**的結構。
* 所有**自動化處理**都由框架完成。
* 依賴項不僅能從請求中提取資料,還能**對 API 的路徑操作進行強化**,並自動生成文檔。
* 即使是依賴項中定義的*路徑操作參數*,也會**自動進行驗證**。
* 支持複雜的用戶身份驗證系統、**資料庫連接**等。
* 不與資料庫、前端等進行強制綁定,但能輕鬆整合它們。
### 無限制「擴充功能」
或者說,無需其他額外配置,直接導入並使用你所需要的程式碼。
任何整合都被設計得非常簡單易用(通過依賴注入),你只需用與*路徑操作*相同的結構和語法,用兩行程式碼就能為你的應用程式建立一個「擴充功能」。
### 測試
* 100% 的<abbr title="有自動測試的程式碼">測試覆蓋率</abbr>。
* 100% 的程式碼有<abbr title="Python 型別註釋,有了這個你的編輯器和外部工具可以給你更好的支援">型別註釋</abbr>。
* 已能夠在生產環境應用程式中使用。
## Starlette 特性
**FastAPI** 完全相容且基於 <a href="https://www.starlette.dev/" class="external-link" target="_blank"><strong>Starlette</strong></a>。所以,你有其他的 Starlette 程式碼也能正常運作。FastAPI 繼承了 Starlette 的所有功能,如果你已經知道或者使用過 Starlette,大部分的功能會以相同的方式運作。
通過 **FastAPI** 你可以獲得所有 **Starlette** 的特性(FastAPI 就像加強版的 Starlette):
* 性能極其出色。它是 <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">Python 可用的最快框架之一,和 **NodeJS****Go** 相當</a>。
* **支援 WebSocket**。
* 能在行程內處理背景任務。
* 支援啟動和關閉事件。
* 有基於 HTTPX 的測試用戶端。
* 支援 **CORS**、GZip、靜態檔案、串流回應。
* 支援 **Session 和 Cookie**
* 100% 測試覆蓋率。
* 100% 型別註釋的程式碼庫。
## Pydantic 特性
**FastAPI** 完全相容且基於 <a href="https://docs.pydantic.dev/" class="external-link" target="_blank"><strong>Pydantic</strong></a>。所以,你有其他 Pydantic 程式碼也能正常工作。
相容包括基於 Pydantic 的外部函式庫, 例如用於資料庫的 <abbr title="Object-Relational Mapper">ORM</abbr>s, <abbr title="Object-Document Mapper">ODM</abbr>s。
這也意味著在很多情況下,你可以把從請求中獲得的物件**直接傳到資料庫**,因為所有資料都會自動進行驗證。
反之亦然,在很多情況下,你也可以把從資料庫中獲取的物件**直接傳給客戶端**。
通過 **FastAPI** 你可以獲得所有 **Pydantic** 的特性(FastAPI 基於 Pydantic 做了所有的資料處理):
* **更簡單**
* 不需要學習新的 micro-language 來定義結構。
* 如果你知道 Python 型別,你就知道如何使用 Pydantic。
* 和你的 **<abbr title="Integrated Development Environment,和程式碼編輯器類似">IDE</abbr>/<abbr title="一個檢查程式碼錯誤的工具">linter</abbr>/brain** 都能好好配合:
* 因為 Pydantic 的資料結構其實就是你自己定義的類別實例,所以自動補齊、linting、mypy 以及你的直覺都能很好地在經過驗證的資料上發揮作用。
* 驗證**複雜結構**
* 使用 Pydantic 模型時,你可以把資料結構分層設計,並且用 Python 的 `List``Dict` 等型別來定義。
* 驗證器讓我們可以輕鬆地定義和檢查複雜的資料結構,並把它們轉換成 JSON Schema 進行記錄。
* 你可以擁有深層**巢狀的 JSON** 物件,並對它們進行驗證和註釋。
* **可擴展**
* Pydantic 讓我們可以定義客製化的資料型別,或者你可以使用帶有 validator 裝飾器的方法來擴展模型中的驗證功能。
* 100% 測試覆蓋率。
+13
View File
@@ -0,0 +1,13 @@
# 使用指南 - 範例集
在這裡,你將會看到**不同主題**的範例或「如何使用」的指南。
大多數這些想法都是**獨立**的,在大多數情況下,你只需要研究那些直接適用於**你的專案**的東西。
如果有些東西看起來很有趣且對你的專案很有用的話再去讀它,否則你可能可以跳過它們。
/// tip
如果你想要以結構化的方式**學習 FastAPI**(推薦),請前往[教學 - 使用者指南](../tutorial/index.md){.internal-link target=_blank}逐章閱讀。
///
+468
View File
@@ -0,0 +1,468 @@
<p align="center">
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>FastAPI 框架,高效能,易於學習,快速開發,適用於生產環境</em>
</p>
<p align="center">
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
<img src="https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master" alt="Test">
</a>
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi" target="_blank">
<img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg" alt="Coverage">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package" alt="Package version">
</a>
<a href="https://pypi.org/project/fastapi" target="_blank">
<img src="https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058" alt="Supported Python versions">
</a>
</p>
---
**文件** <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**程式碼** <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
---
FastAPI 是一個現代、快速(高效能)的 web 框架,用於 Python 並採用標準 Python 型別提示。
主要特點包含:
- **快速** 非常高的效能,可與 **NodeJS****Go** 效能相當 (歸功於 Starlette and Pydantic)。 [FastAPI 是最快的 Python web 框架之一](#performance)。
- **極速開發**: 提高開發功能的速度約 200% 至 300%。 \*
- **更少的 Bug**: 減少約 40% 的人為(開發者)導致的錯誤。 \*
- **直覺**: 具有出色的編輯器支援,處處都有<abbr title="也被稱為自動完成、IntelliSense">自動補全</abbr>以減少偵錯時間。
- **簡單**: 設計上易於使用和學習,大幅減少閱讀文件的時間。
- **簡潔**: 最小化程式碼重複性。可以通過不同的參數聲明來實現更豐富的功能,和更少的錯誤。
- **穩健**: 立即獲得生產級可用的程式碼,還有自動生成互動式文件。
- **標準化**: 基於 (且完全相容於) OpenAPIs 的相關標準:<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>(之前被稱為 Swagger)和<a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>。
<small>\* 基於內部開發團隊在建立生產應用程式時的測試預估。</small>
## 贊助
<!-- sponsors -->
{% if sponsors %}
{% for sponsor in sponsors.gold -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor -%}
{%- for sponsor in sponsors.silver -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor %}
{% endif %}
<!-- /sponsors -->
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">其他贊助商</a>
## 評價
"_[...] 近期大量的使用 **FastAPI**。 [...] 目前正在計畫在**微軟**團隊的**機器學習**服務中導入。其中一些正在整合到核心的 **Windows** 產品和一些 **Office** 產品。_"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
"_我們使用 **FastAPI** 來建立產生**預測**結果的 **REST** 伺服器。 [for Ludwig]_"
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
"_**Netflix** 很榮幸地宣布開源**危機管理**協調框架: **Dispatch**! [是使用 **FastAPI** 建構]_"
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
---
"_我對 **FastAPI** 興奮得不得了。它太有趣了!_"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_老實說,你建造的東西看起來非常堅固和精緻。在很多方面,這就是我想要的,看到有人建造它真的很鼓舞人心。_"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_如果您想學習一種用於構建 REST API 的**現代框架**,不能錯過 **FastAPI** [...] 它非常快速、且易於使用和學習 [...]_"
"_我們的 **APIs** 已經改用 **FastAPI** [...] 我想你會喜歡它 [...]_"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> 創辦人 - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
"_如果有人想要建立一個生產環境的 Python API,我強烈推薦 **FastAPI**,它**設計精美**,**使用簡單**且**高度可擴充**,它已成為我們 API 優先開發策略中的**關鍵組件**,並且驅動了許多自動化服務,例如我們的 Virtual TAC Engineer。_"
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
---
## **Typer**,命令列中的 FastAPI
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
如果你不是在開發網頁 API,而是正在開發一個在終端機中運行的<abbr title="Command Line Interface">命令列</abbr>應用程式,不妨嘗試 <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>。
**Typer** 是 FastAPI 的小兄弟。他立志成為命令列的 **FastAPI**。 ⌨️ 🚀
## 安裝需求
FastAPI 是站在以下巨人的肩膀上:
- <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> 負責網頁的部分
- <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> 負責資料的部分
## 安裝
<div class="termy">
```console
$ pip install fastapi
---> 100%
```
</div>
你同時也會需要 ASGI 伺服器用於生產環境,像是 <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> 或 <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>。
<div class="termy">
```console
$ pip install "uvicorn[standard]"
---> 100%
```
</div>
## 範例
### 建立
- 建立一個 python 檔案 `main.py`,並寫入以下程式碼:
```Python
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
<details markdown="1">
<summary>或可以使用 <code>async def</code>...</summary>
如果你的程式使用 `async` / `await`,請使用 `async def`
```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
**注意**
如果你不知道是否會用到,可以查看 _"In a hurry?"_ 章節中,關於 <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` 和 `await` 的部分</a>。
</details>
### 運行
使用以下指令運行伺服器:
<div class="termy">
```console
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
</div>
<details markdown="1">
<summary>關於指令 <code>uvicorn main:app --reload</code>...</summary>
該指令 `uvicorn main:app` 指的是:
- `main``main.py` 檔案(一個 python 的 "模組")。
- `app`:在 `main.py` 檔案中,使用 `app = FastAPI()` 建立的物件。
- `--reload`:程式碼更改後會自動重新啟動,請僅在開發時使用此參數。
</details>
### 檢查
使用瀏覽器開啟 <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>。
你將會看到以下的 JSON 回應:
```JSON
{"item_id": 5, "q": "somequery"}
```
你已經建立了一個具有以下功能的 API:
- 透過路徑 `/` 和 `/items/{item_id}` 接受 HTTP 請求。
- 以上路經都接受 `GET` <em>請求</em>(也被稱為 HTTP _方法_)。
- 路徑 `/items/{item_id}` 有一個 `int` 型別的 `item_id` 參數。
- 路徑 `/items/{item_id}` 有一個 `str` 型別的查詢參數 `q`。
### 互動式 API 文件
使用瀏覽器開啟 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>。
你會看到自動生成的互動式 API 文件(由 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> 生成):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### ReDoc API 文件
使用瀏覽器開啟 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>。
你將看到 ReDoc 文件 (由 <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> 生成)
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## 範例升級
現在繼續修改 `main.py` 檔案,來接收一個帶有 body 的 `PUT` 請求。
我們使用 Pydantic 來使用標準的 Python 型別聲明請求。
```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Union[bool, None] = None
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
伺服器將自動重新載入(因為在上一步中,你向 `uvicorn` 指令添加了 `--reload` 的選項)。
### 互動式 API 文件升級
使用瀏覽器開啟 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>。
- 互動式 API 文件會自動更新,並加入新的 body 請求:
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
- 點擊 "Try it out" 按鈕, 你可以填寫參數並直接與 API 互動:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
- 然後點擊 "Execute" 按鈕,使用者介面將會向 API 發送請求,並將結果顯示在螢幕上:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### ReDoc API 文件升級
使用瀏覽器開啟 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>。
- ReDoc API 文件會自動更新,並加入新的參數和 body 請求:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### 總結
總結來說, 你就像宣告函式的參數型別一樣,只宣告了一次請求參數和請求主體參數等型別。
你使用 Python 標準型別來完成聲明。
你不需要學習新的語法、類別、方法或函式庫等等。
只需要使用 **Python 以上的版本**。
舉個範例,比如宣告 int 的型別:
```Python
item_id: int
```
或是一個更複雜的 `Item` 模型:
```Python
item: Item
```
在進行一次宣告後,你將獲得:
- 編輯器支援:
- 自動補全
- 型別檢查
- 資料驗證:
- 驗證失敗時自動生成清楚的錯誤訊息
- 可驗證多層巢狀的 JSON 物件
- <abbr title="也被稱為: 序列化或解析">轉換</abbr>輸入的資料: 轉換來自網路請求到 Python 資料型別。包含以下數據:
- JSON
- 路徑參數
- 查詢參數
- Cookies
- 請求標頭
- 表單
- 文件
- <abbr title="也被稱為: 序列化或解析">轉換</abbr>輸出的資料: 轉換 Python 資料型別到網路傳輸的 JSON:
- 轉換 Python 型別 (`str`、 `int`、 `float`、 `bool`、 `list` 等)
- `datetime` 物件
- `UUID` 物件
- 數據模型
- ...還有其他更多
- 自動生成的 API 文件,包含 2 種不同的使用介面:
- Swagger UI
- ReDoc
---
回到前面的的程式碼範例,**FastAPI** 還會:
- 驗證 `GET` 和 `PUT` 請求路徑中是否包含 `item_id`。
- 驗證 `GET` 和 `PUT` 請求中的 `item_id` 是否是 `int` 型別。
- 如果驗證失敗,將會返回清楚有用的錯誤訊息。
- 查看 `GET` 請求中是否有命名為 `q` 的查詢參數 (例如 `http://127.0.0.1:8000/items/foo?q=somequery`)。
- 因為 `q` 參數被宣告為 `= None`,所以是選填的。
- 如果沒有宣告 `None`,則此參數將會是必填 (例如 `PUT` 範例的請求 body)。
- 對於 `PUT` 的請求 `/items/{item_id}`,將會讀取 body 為 JSON
- 驗證是否有必填屬性 `name` 且型別是 `str`。
- 驗證是否有必填屬性 `price` 且型別是 `float`。
- 驗證是否有選填屬性 `is_offer` 且型別是 `bool`。
- 以上驗證都適用於多層次巢狀 JSON 物件。
- 自動轉換 JSON 格式。
- 透過 OpenAPI 文件來記錄所有內容,可以被用於:
- 互動式文件系統。
- 自動為多種程式語言生成用戶端的程式碼。
- 提供兩種交互式文件介面。
---
雖然我們只敘述了表面的功能,但其實你已經理解了它是如何執行。
試著修改以下程式碼:
```Python
return {"item_name": item.name, "item_id": item_id}
```
從:
```Python
... "item_name": item.name ...
```
修改為:
```Python
... "item_price": item.price ...
```
然後觀察你的編輯器,會自動補全並且還知道他們的型別:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
有關更多功能的完整範例,可以參考 <a href="https://fastapi.tiangolo.com/tutorial/">教學 - 使用者指南</a>。
**劇透警告**: 教學 - 使用者指南內容有:
- 對來自不同地方的**參數**進行宣告:像是 **headers**, **cookies**, **form 表單**以及**上傳檔案**。
- 如何設定 **驗證限制** 像是 `maximum_length` or `regex`。
- 簡單且非常容易使用的 **<abbr title="也被稱為元件、資源、提供者、服務或是注入">依賴注入</abbr>** 系統。
- 安全性和身份驗證,包含提供支援 **OAuth2**、**JWT tokens** 和 **HTTP Basic** 驗證。
- 更進階 (但同樣簡單) 的宣告 **多層次的巢狀 JSON 格式** (感謝 Pydantic)。
- **GraphQL** 與 <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> 以及其他的相關函式庫進行整合。
- 更多其他的功能 (感謝 Starlette) 像是:
- **WebSockets**
- 於 HTTPX 和 `pytest` 的非常簡單測試
- **CORS**
- **Cookie Sessions**
- ...以及更多
## 效能
來自獨立機構 TechEmpower 的測試結果,顯示在 Uvicorn 執行下的 **FastAPI** 是 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">最快的 Python 框架之一</a> 僅次於 Starlette 和 Uvicorn 本身 (兩者是 FastAPI 的底層)。 (\*)
想了解更多訊息,可以參考 <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">測試結果</a>。
## 可選的依賴套件
用於 Pydantic
- <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - 用於電子郵件驗證。
- <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - 用於設定管理。
- <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - 用於與 Pydantic 一起使用的額外型別。
用於 Starlette
- <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - 使用 `TestClient`時必須安裝。
- <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - 使用預設的模板配置時必須安裝。
- <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - 需要使用 `request.form()` 對表單進行<abbr title="轉換來自表單的 HTTP 請求到 Python 資料型別"> "解析" </abbr>時安裝。
- <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - 需要使用 `SessionMiddleware` 支援時安裝。
- <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - 用於支援 Starlette 的 `SchemaGenerator` (如果你使用 FastAPI,可能不需要它)。
用於 FastAPI / Starlette
- <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - 用於加載和運行應用程式的服務器。
- <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - 使用 `ORJSONResponse`時必須安裝。
- <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 使用 `UJSONResponse` 時必須安裝。
你可以使用 `pip install "fastapi[all]"` 來安裝這些所有依賴套件。
## 授權
該項目遵循 MIT 許可協議。
+5
View File
@@ -0,0 +1,5 @@
# 學習
以下是學習 FastAPI 的入門介紹和教學。
你可以將其視為一本**書籍**或一門**課程**,這是**官方**認可並推薦的 FastAPI 學習方式。 😎
+3
View File
@@ -0,0 +1,3 @@
# 資源
額外的資源、外部連結、文章等。 ✈️
+331
View File
@@ -0,0 +1,331 @@
# 第一步
最簡單的 FastAPI 檔案可能看起來像這樣:
{* ../../docs_src/first_steps/tutorial001.py *}
將其複製到一個名為 `main.py` 的文件中。
執行即時重新載入伺服器(live server):
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
│ │
│ 🐍 main.py │
│ │
╰──────────────────────╯
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
<font color="#3465A4">INFO </font> Found importable FastAPI app
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
│ │
│ <span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span> │
│ │
╰──────────────────────────╯
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
<span style="background-color:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ </font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"> │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: [&apos;/home/user/code/awesomeapp&apos;]
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
<font color="#4E9A06">INFO</font>: Waiting for application startup.
<font color="#4E9A06">INFO</font>: Application startup complete.
```
</div>
在輸出中,有一列類似於:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
那列顯示了你的應用程式正在本地端機器上運行的 URL。
### 查看它
在瀏覽器中打開 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
你將看到如下的 JSON 回應:
```JSON
{"message": "Hello World"}
```
### 互動式 API 文件
現在,前往 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
你將看到自動的互動式 API 文件(由 <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> 提供):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### 替代 API 文件
現在,前往 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
你將看到另一種自動文件(由 <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> 提供):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### OpenAPI
**FastAPI** 使用定義 API 的 **OpenAPI** 標準來生成一個 「schema」 與你的所有 API。
#### 「Schema」
「schema」是對某個事物的定義或描述。它並不是實作它的程式碼,而僅僅是一個抽象的描述。
#### API 「schema」
在這種情況下,<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> 是一個規範,它規定了如何定義 API 的 schema。
這個 schema 定義包含了你的 API 路徑、可能接收的參數等內容。
#### 資料 「schema」
「schema」這個術語也可能指某些資料的結構,比如 JSON 內容的結構。
在這種情況下,它指的是 JSON 的屬性、資料型別等。
#### OpenAPI 和 JSON Schema
OpenAPI 定義了 API 的 schema。這個 schema 包含了使用 **JSON Schema** 定義的資料,這是 JSON 資料 schema 的標準。
#### 檢查 `openapi.json`
如果你好奇原始的 OpenAPI schema 長什麼樣子,FastAPI 會自動生成一個包含所有 API 描述的 JSON (schema)。
你可以直接在 <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a> 查看它。
它會顯示一個 JSON,類似於:
```JSON
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
...
```
#### OpenAPI 的用途
OpenAPI schema 驅動了兩個互動式文件系統。
而且有許多替代方案,所有這些都是基於 OpenAPI。你可以輕鬆地將任何這些替代方案添加到使用 **FastAPI** 建置的應用程式中。
你也可以用它自動生成程式碼,讓前端、手機應用程式或物聯網設備等與你的 API 進行通訊。
## 逐步回顧
### 第一步:引入 `FastAPI`
{* ../../docs_src/first_steps/tutorial001.py h1[1] *}
`FastAPI` 是一個 Python 類別,提供所有 API 的全部功能。
/// note | Technical Details
`FastAPI` 是一個直接繼承自 `Starlette` 的類別。
你同樣可以透過 `FastAPI` 來使用 <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> 所有的功能。
///
### 第二步:建立一個 `FastAPI` 「實例」
{* ../../docs_src/first_steps/tutorial001.py h1[3] *}
這裡的 `app` 變數將會是 `FastAPI` 類別的「實例」。
這將是你建立所有 API 的主要互動點。
### 第三步:建立一個 *路徑操作*
#### 路徑
這裡的「路徑」指的是 URL 中自第一個 `/` 以後的部分。
例如,在 URL 中:
```
https://example.com/items/foo
```
……的路徑將會是:
```
/items/foo
```
/// info
「路徑」也常被稱為「端點 endpoint」或「路由 route」。
///
在建置 API 時,「路徑」是分離「關注點」和「資源」的主要方式。
#### 操作
這裡的「操作」指的是 HTTP 的「方法」之一。
其中包括:
* `POST`
* `GET`
* `PUT`
* `DELETE`
……以及更少見的:
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
在 HTTP 協定中,你可以使用這些「方法」之一(或更多)與每個路徑進行通信。
---
在建置 API 時,你通常使用這些特定的 HTTP 方法來執行特定的動作。
通常你使用:
* `POST`:用來建立資料。
* `GET`:用來讀取資料。
* `PUT`:用來更新資料。
* `DELETE`:用來刪除資料。
所以,在 OpenAPI 中,每個 HTTP 方法都被稱為「操作」。
我們將會稱它們為「**操作**」。
#### 定義一個 *路徑操作裝飾器*
{* ../../docs_src/first_steps/tutorial001.py h1[6] *}
`@app.get("/")` 告訴 **FastAPI** 那個函式負責處理請求:
* 路徑 `/`
* 使用 <abbr title="HTTP GET 方法"><code>get</code>操作</abbr>
/// info | `@decorator` Info
Python 中的 `@something` 語法被稱為「裝飾器」。
你把它放在一個函式上面。像一個漂亮的裝飾帽子(我猜這是術語的來源)。
一個「裝飾器」會對下面的函式做一些事情。
在這種情況下,這個裝飾器告訴 **FastAPI** 那個函式對應於 **路徑** `/` 和 **操作** `get`.
這就是「**路徑操作裝飾器**」。
///
你也可以使用其他的操作:
* `@app.post()`
* `@app.put()`
* `@app.delete()`
以及更少見的:
* `@app.options()`
* `@app.head()`
* `@app.patch()`
* `@app.trace()`
/// tip
你可以自由地使用每個操作(HTTP 方法)。
**FastAPI** 不強制任何特定的意義。
這裡的資訊作為一個指南,而不是要求。
例如,當使用 GraphQL 時,你通常只使用 `POST` 操作。
///
### 第四步:定義 **路徑操作函式**
這是我們的「**路徑操作函式**」:
* **path**: 是 `/`.
* **operation**: 是 `get`.
* **function**: 是裝飾器下面的函式(在 `@app.get("/")` 下面)。
{* ../../docs_src/first_steps/tutorial001.py h1[7] *}
這就是一個 Python 函式。
它將會在 **FastAPI** 收到一個請求時被呼叫,使用 `GET` 操作。
在這種情況下,它是一個 `async` 函式。
---
你可以將它定義為一個正常的函式,而不是 `async def`:
{* ../../docs_src/first_steps/tutorial003.py h1[7] *}
/// note
如果你不知道差別,請查看 [Async: *"In a hurry?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
///
### 第五步:回傳內容
{* ../../docs_src/first_steps/tutorial001.py h1[8] *}
你可以返回一個 `dict`、`list`、單個值作為 `str`、`int` 等。
你也可以返回 Pydantic 模型(稍後你會看到更多關於這方面的內容)。
有很多其他物件和模型會自動轉換為 JSON(包括 ORMs,等等)。試用你最喜歡的,很有可能它們已經有支援。
## 回顧
* 引入 `FastAPI`.
* 建立一個 `app` 實例。
* 寫一個 **路徑操作裝飾器** 使用裝飾器像 `@app.get("/")`。
* 定義一個 **路徑操作函式**;例如,`def root(): ...`。
* 使用命令 `fastapi dev` 執行開發伺服器。
+102
View File
@@ -0,0 +1,102 @@
# 教學 - 使用者指南
本教學將一步一步展示如何使用 **FastAPI** 及其大多數功能。
每個部分都是在前一部分的基礎上逐步建置的,但內容結構是按主題分開的,因此你可以直接跳到任何特定的部分,解決你具體的 API 需求。
它也被設計成可作為未來的參考,讓你隨時回來查看所需的內容。
## 運行程式碼
所有程式碼區塊都可以直接複製和使用(它們實際上是經過測試的 Python 檔案)。
要運行任何範例,請將程式碼複製到 `main.py` 檔案,並使用以下命令啟動 `fastapi dev`
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
│ │
│ 🐍 main.py │
│ │
╰──────────────────────╯
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
<font color="#3465A4">INFO </font> Found importable FastAPI app
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
│ │
│ <span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span> │
│ │
╰──────────────────────────╯
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
<span style="background-color:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ </font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"> │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: [&apos;/home/user/code/awesomeapp&apos;]
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
<font color="#4E9A06">INFO</font>: Waiting for application startup.
<font color="#4E9A06">INFO</font>: Application startup complete.
</pre>
```
</div>
**強烈建議**你編寫或複製程式碼、進行修改並在本地端運行。
在編輯器中使用它,才能真正體會到 FastAPI 的好處,可以看到你只需編寫少量程式碼,以及所有的型別檢查、自動補齊等功能。
---
## 安裝 FastAPI
第一步是安裝 FastAPI。
確保你建立一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},啟用它,然後**安裝 FastAPI**
<div class="termy">
```console
$ pip install "fastapi[standard]"
---> 100%
```
</div>
/// note
當你使用 `pip install "fastapi[standard]"` 安裝時,會包含一些預設的可選標準依賴項。
如果你不想包含那些可選的依賴項,你可以使用 `pip install fastapi` 來安裝。
///
## 進階使用者指南
還有一個**進階使用者指南**你可以稍後閱讀。
**進階使用者指南**建立在這個教學之上,使用相同的概念,並教你一些額外的功能。
但首先你應該閱讀**教學 - 使用者指南**(你正在閱讀的內容)。
它被設計成你可以使用**教學 - 使用者指南**來建立一個完整的應用程式,然後根據你的需求,使用一些額外的想法來擴展它。
@@ -0,0 +1,68 @@
# 查詢參數模型
如果你有一組具有相關性的**查詢參數**,你可以建立一個 **Pydantic 模型**來聲明它們。
這將允許你在**多個地方**去**重複使用模型**,並且一次性為所有參數聲明驗證和元資料 (metadata)。😎
/// note
FastAPI 從 `0.115.0` 版本開始支援這個特性。🤓
///
## 使用 Pydantic 模型的查詢參數
在一個 **Pydantic 模型**中聲明你需要的**查詢參數**,然後將參數聲明為 `Query`
{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
**FastAPI** 將會從請求的**查詢參數**中**提取**出**每個欄位**的資料,並將其提供給你定義的 Pydantic 模型。
## 查看文件
你可以在 `/docs` 頁面的 UI 中查看查詢參數:
<div class="screenshot">
<img src="/img/tutorial/query-param-models/image01.png">
</div>
## 禁止額外的查詢參數
在一些特殊的使用場景中(可能不是很常見),你可能希望**限制**你要收到的查詢參數。
你可以使用 Pydantic 的模型設定來 `forbid`(禁止)任何 `extra`(額外)欄位:
{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
如果客戶端嘗試在**查詢參數**中發送一些**額外的**資料,他們將會收到一個**錯誤**回應。
例如,如果客戶端嘗試發送一個值為 `plumbus``tool` 查詢參數,如:
```http
https://example.com/items/?limit=10&tool=plumbus
```
他們將收到一個**錯誤**回應,告訴他們查詢參數 `tool` 是不允許的:
```json
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["query", "tool"],
"msg": "Extra inputs are not permitted",
"input": "plumbus"
}
]
}
```
## 總結
你可以使用 **Pydantic 模型**在 **FastAPI** 中聲明**查詢參數**。😎
/// tip
劇透警告:你也可以使用 Pydantic 模型來聲明 cookie 和 headers,但你將在本教學的後面部分閱讀到這部分內容。🤫
///
+844
View File
@@ -0,0 +1,844 @@
# 虛擬環境
當你在 Python 專案中工作時,你可能會需要使用一個**虛擬環境**(或類似的機制)來隔離你為每個專案安裝的套件。
/// info
如果你已經了解虛擬環境,知道如何建立和使用它們,你可以考慮跳過這一部分。🤓
///
/// tip
**虛擬環境**和**環境變數**是不同的。
**環境變數**是系統中的一個變數,可以被程式使用。
**虛擬環境**是一個包含一些檔案的目錄。
///
/// info
這個頁面將教你如何使用**虛擬環境**以及了解它們的工作原理。
如果你計畫使用一個**可以為你管理一切的工具**(包括安裝 Python),試試 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>。
///
## 建立一個專案
首先,為你的專案建立一個目錄。
我(指原作者 —— 譯者注)通常會在我的主目錄下建立一個名為 `code` 的目錄。
在這個目錄下,我再為每個專案建立一個目錄。
<div class="termy">
```console
// 進入主目錄
$ cd
// 建立一個用於存放所有程式碼專案的目錄
$ mkdir code
// 進入 code 目錄
$ cd code
// 建立一個用於存放這個專案的目錄
$ mkdir awesome-project
// 進入這個專案的目錄
$ cd awesome-project
```
</div>
## 建立一個虛擬環境
在開始一個 Python 專案的**第一時間****<abbr title="還有其他做法,此處僅作為一個簡單的指引">在你的專案內部</abbr>**建立一個虛擬環境。
/// tip
你只需要**在每個專案中操作一次**,而不是每次工作時都操作。
///
//// tab | `venv`
你可以使用 Python 自帶的 `venv` 模組來建立一個虛擬環境。
<div class="termy">
```console
$ python -m venv .venv
```
</div>
/// details | 上述命令的含義
* `python`: 使用名為 `python` 的程式
* `-m`: 以腳本的方式呼叫一個模組,我們將告訴它接下來使用哪個模組
* `venv`: 使用名為 `venv` 的模組,這個模組通常隨 Python 一起安裝
* `.venv`: 在新目錄 `.venv` 中建立虛擬環境
///
////
//// tab | `uv`
如果你安裝了 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>,你也可以使用它來建立一個虛擬環境。
<div class="termy">
```console
$ uv venv
```
</div>
/// tip
預設情況下,`uv` 會在一個名為 `.venv` 的目錄中建立一個虛擬環境。
但你可以透過傳遞一個額外的引數來自訂它,指定目錄的名稱。
///
////
這個命令會在一個名為 `.venv` 的目錄中建立一個新的虛擬環境。
/// details | `.venv`,或是其他名稱
你可以在不同的目錄下建立虛擬環境,但通常我們會把它命名為 `.venv`
///
## 啟動虛擬環境
啟動新的虛擬環境來確保你運行的任何 Python 指令或安裝的套件都能使用到它。
/// tip
**每次**開始一個**新的終端會話**來在這個專案工作時,你都需要執行這個操作。
///
//// tab | Linux, macOS
<div class="termy">
```console
$ source .venv/bin/activate
```
</div>
////
//// tab | Windows PowerShell
<div class="termy">
```console
$ .venv\Scripts\Activate.ps1
```
</div>
////
//// tab | Windows Bash
或者,如果你在 Windows 上使用 Bash(例如 <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
```console
$ source .venv/Scripts/activate
```
</div>
////
/// tip
每次你在這個環境中安裝一個**新的套件**時,都需要**重新啟動**這個環境。
這麼做確保了當你使用一個由這個套件安裝的**終端(<abbr title="命令列介面">CLI</abbr>)程式**時,你使用的是你的虛擬環境中的程式,而不是全域安裝、可能版本不同的程式。
///
## 檢查虛擬環境是否啟動
檢查虛擬環境是否啟動(前面的指令是否生效)。
/// tip
這是**非必需的**,但這是一個很好的方法,可以**檢查**一切是否按預期工作,以及你是否使用了你打算使用的虛擬環境。
///
//// tab | Linux, macOS, Windows Bash
<div class="termy">
```console
$ which python
/home/user/code/awesome-project/.venv/bin/python
```
</div>
如果它顯示了在你專案(在這個例子中是 `awesome-project`)的 `.venv/bin/python` 中的 `python` 二進位檔案,那麼它就生效了。🎉
////
//// tab | Windows PowerShell
<div class="termy">
```console
$ Get-Command python
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
</div>
如果它顯示了在你專案(在這個例子中是 `awesome-project`)的 `.venv\Scripts\python` 中的 `python` 二進位檔案,那麼它就生效了。🎉
////
## 升級 `pip`
/// tip
如果你使用 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a> 來安裝內容,而不是 `pip`,那麼你就不需要升級 `pip`。😎
///
如果你使用 `pip` 來安裝套件(它是 Python 的預設元件),你應該將它**升級**到最新版本。
在安裝套件時出現的許多奇怪的錯誤都可以透過先升級 `pip` 來解決。
/// tip
通常你只需要在建立虛擬環境後**執行一次**這個操作。
///
確保虛擬環境是啟動的(使用上面的指令),然後運行:
<div class="termy">
```console
$ python -m pip install --upgrade pip
---> 100%
```
</div>
## 加入 `.gitignore`
如果你使用 **Git**(這是你應該使用的),加入一個 `.gitignore` 檔案來排除你的 `.venv` 中的所有內容。
/// tip
如果你使用 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a> 來建立虛擬環境,它會自動為你完成這個操作,你可以跳過這一步。😎
///
/// tip
通常你只需要在建立虛擬環境後**執行一次**這個操作。
///
<div class="termy">
```console
$ echo "*" > .venv/.gitignore
```
</div>
/// details | 上述指令的含義
- `echo "*"`: 將在終端中「顯示」文本 `*`(接下來的部分會對這個操作進行一些修改)
- `>`: 使左邊的指令顯示到終端的任何內容實際上都不會被顯示,而是會被寫入到右邊的檔案中
- `.gitignore`: 被寫入文本的檔案的名稱
`*` 對於 Git 來說意味著「所有內容」。所以,它會忽略 `.venv` 目錄中的所有內容。
該指令會建立一個名為 .gitignore 的檔案,內容如下:
```gitignore
*
```
///
## 安裝套件
在啟用虛擬環境後,你可以在其中安裝套件。
/// tip
當你需要安裝或升級套件時,執行本操作**一次**;
如果你需要再升級版本或新增套件,你可以**再次執行此操作**。
///
### 直接安裝套件
如果你急於安裝,不想使用檔案來聲明專案的套件依賴,你可以直接安裝它們。
/// tip
將程式所需的套件及其版本放在檔案中(例如 `requirements.txt``pyproject.toml`)是個好(而且非常好)的主意。
///
//// tab | `pip`
<div class="termy">
```console
$ pip install "fastapi[standard]"
---> 100%
```
</div>
////
//// tab | `uv`
如果你有 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
```console
$ uv pip install "fastapi[standard]"
---> 100%
```
</div>
////
### 從 `requirements.txt` 安裝
如果你有一個 `requirements.txt` 檔案,你可以使用它來安裝其中的套件。
//// tab | `pip`
<div class="termy">
```console
$ pip install -r requirements.txt
---> 100%
```
</div>
////
//// tab | `uv`
如果你有 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
```console
$ uv pip install -r requirements.txt
---> 100%
```
</div>
////
/// details | 關於 `requirements.txt`
一個包含一些套件的 `requirements.txt` 檔案看起來應該是這樣的:
```requirements.txt
fastapi[standard]==0.113.0
pydantic==2.8.0
```
///
## 執行程式
在啟用虛擬環境後,你可以執行你的程式,它將使用虛擬環境中的 Python 和你在其中安裝的套件。
<div class="termy">
```console
$ python main.py
Hello World
```
</div>
## 設定編輯器
你可能會用到編輯器,請確保設定它使用你建立的相同虛擬環境(它可能會自動偵測到),以便你可以獲得自動完成和内嵌錯誤提示。
例如:
* <a href="https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment" class="external-link" target="_blank">VS Code</a>
* <a href="https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html" class="external-link" target="_blank">PyCharm</a>
/// tip
通常你只需要在建立虛擬環境時執行此操作**一次**。
///
## 退出虛擬環境
當你完成工作後,你可以**退出**虛擬環境。
<div class="termy">
```console
$ deactivate
```
</div>
這樣,當你執行 `python` 時它不會嘗試從已安裝套件的虛擬環境中執行。
## 開始工作
現在你已經準備好開始你的工作了。
/// tip
你想要理解上面的所有內容嗎?
繼續閱讀。👇🤓
///
## 為什麼要使用虛擬環境
你需要安裝 <a href="https://www.python.org/" class="external-link" target="_blank">Python</a> 才能使用 FastAPI。
接下來,你需要**安裝** FastAPI 以及你想使用的其他**套件**。
要安裝套件,你通常會使用隨 Python 一起提供的 `pip` 指令(或類似的替代工具)。
然而,如果你直接使用 `pip`,套件將會安裝在你的**全域 Python 環境**中(即 Python 的全域安裝)。
### 存在的問題
那麼,在全域 Python 環境中安裝套件有什麼問題呢?
有時候,你可能會開發許多不同的程式,而這些程式各自依賴於**不同的套件**;有些專案甚至需要依賴於**相同套件的不同版本**。😱
例如,你可能會建立一個名為 `philosophers-stone` 的專案,這個程式依賴於另一個名為 **`harry` 的套件,並使用版本 `1`**。因此,你需要安裝 `harry`。
```mermaid
flowchart LR
stone(philosophers-stone) -->|需要| harry-1[harry v1]
```
然而,在此之後,你又建立了另一個名為 `prisoner-of-azkaban` 的專案,而這個專案也依賴於 `harry`,但需要的是 **`harry` 版本 `3`**。
```mermaid
flowchart LR
azkaban(prisoner-of-azkaban) --> |需要| harry-3[harry v3]
```
現在的問題是,如果你在全域環境中安裝套件而不是在本地**虛擬環境**中,你將面臨選擇安裝哪個版本的 `harry` 的困境。
如果你想運行 `philosophers-stone`,你需要先安裝 `harry` 版本 `1`,例如:
<div class="termy">
```console
$ pip install "harry==1"
```
</div>
然後你會在全域 Python 環境中安裝 `harry` 版本 `1`。
```mermaid
flowchart LR
subgraph global[全域環境]
harry-1[harry v1]
end
subgraph stone-project[專案 philosophers-stone]
stone(philosophers-stone) -->|需要| harry-1
end
```
但如果你想運行 `prisoner-of-azkaban`,你需要解除安裝 `harry` 版本 `1` 並安裝 `harry` 版本 `3`(或者只要你安裝版本 `3`,版本 `1` 就會自動移除)。
<div class="termy">
```console
$ pip install "harry==3"
```
</div>
於是,你在全域 Python 環境中安裝了 `harry` 版本 `3`。
如果你再次嘗試運行 `philosophers-stone`,很可能會**無法正常運作**,因為它需要的是 `harry` 版本 `1`。
```mermaid
flowchart LR
subgraph global[全域環境]
harry-1[<strike>harry v1</strike>]
style harry-1 fill:#ccc,stroke-dasharray: 5 5
harry-3[harry v3]
end
subgraph stone-project[專案 philosophers-stone]
stone(philosophers-stone) -.-x|⛔️| harry-1
end
subgraph azkaban-project[專案 prisoner-of-azkaban]
azkaban(prisoner-of-azkaban) --> |需要| harry-3
end
```
/// tip
Python 套件在推出**新版本**時通常會儘量**避免破壞性更改**,但最好還是要謹慎,在安裝新版本前進行測試,以確保一切能正常運行。
///
現在,想像一下如果有**許多**其他**套件**,它們都是你的**專案所依賴的**。這樣是非常難以管理的。你可能會發現有些專案使用了一些**不相容的套件版本**,而無法得知為什麼某些程式無法正常運作。
此外,取決於你的操作系統(例如 Linux、Windows、macOS),它可能已經預先安裝了 Python。在這種情況下,它可能已經有一些系統所需的套件和特定版本。如果你在全域 Python 環境中安裝套件,可能會**破壞**某些隨作業系統一起安裝的程式。
## 套件安裝在哪裡
當你安裝 Python 時,它會在你的電腦中建立一些目錄並放置一些檔案。
其中一些目錄專門用來存放你所安裝的所有套件。
當你運行:
<div class="termy">
```console
// 先別去運行這個指令,這只是個示例 🤓
$ pip install "fastapi[standard]"
---> 100%
```
</div>
這會從 <a href="https://pypi.org/project/fastapi/" class="external-link" target="_blank">PyPI</a> 下載一個壓縮檔案,其中包含 FastAPI 的程式碼。
它還會**下載** FastAPI 所依賴的其他套件的檔案。
接著,它會**解壓**所有這些檔案,並將它們放在你的電腦中的某個目錄中。
預設情況下,這些下載和解壓的檔案會放置於隨 Python 安裝的目錄中,即**全域環境**。
## 什麼是虛擬環境
解決套件都安裝在全域環境中的問題方法是為你所做的每個專案使用一個**虛擬環境**。
虛擬環境是一個**目錄**,與全域環境非常相似,你可以在其中針對某個專案安裝套件。
這樣,每個專案都會有自己的虛擬環境(`.venv` 目錄),其中包含自己的套件。
```mermaid
flowchart TB
subgraph stone-project[專案 philosophers-stone]
stone(philosophers-stone) --->|需要| harry-1
subgraph venv1[.venv]
harry-1[harry v1]
end
end
subgraph azkaban-project[專案 prisoner-of-azkaban]
azkaban(prisoner-of-azkaban) --->|需要| harry-3
subgraph venv2[.venv]
harry-3[harry v3]
end
end
stone-project ~~~ azkaban-project
```
## 啟用虛擬環境意味著什麼
當你啟用了虛擬環境,例如:
//// tab | Linux, macOS
<div class="termy">
```console
$ source .venv/bin/activate
```
</div>
////
//// tab | Windows PowerShell
<div class="termy">
```console
$ .venv\Scripts\Activate.ps1
```
</div>
////
//// tab | Windows Bash
或者如果你在 Windows 上使用 Bash(例如 <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
<div class="termy">
```console
$ source .venv/Scripts/activate
```
</div>
////
這個命令會建立或修改一些[環境變數](environment-variables.md){.internal-link target=_blank},這些環境變數將在接下來的指令中可用。
其中之一是 `PATH` 變數。
/// tip
你可以在 [環境變數](environment-variables.md#path-environment-variable){.internal-link target=_blank} 部分了解更多關於 `PATH` 環境變數的內容。
///
啟用虛擬環境會將其路徑 `.venv/bin`(在 Linux 和 macOS 上)或 `.venv\Scripts`(在 Windows 上)加入到 `PATH` 環境變數中。
假設在啟用環境之前,`PATH` 變數看起來像這樣:
//// tab | Linux, macOS
```plaintext
/usr/bin:/bin:/usr/sbin:/sbin
```
這意味著系統會在以下目錄中查找程式:
* `/usr/bin`
* `/bin`
* `/usr/sbin`
* `/sbin`
////
//// tab | Windows
```plaintext
C:\Windows\System32
```
這意味著系統會在以下目錄中查找程式:
* `C:\Windows\System32`
////
啟用虛擬環境後,`PATH` 變數會變成這樣:
//// tab | Linux, macOS
```plaintext
/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
這意味著系統現在會首先在以下目錄中查找程式:
```plaintext
/home/user/code/awesome-project/.venv/bin
```
然後再在其他目錄中查找。
因此,當你在終端機中輸入 `python` 時,系統會在以下目錄中找到 Python 程式:
```plaintext
/home/user/code/awesome-project/.venv/bin/python
```
並使用這個。
////
//// tab | Windows
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
```
這意味著系統現在會首先在以下目錄中查找程式:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts
```
然後再在其他目錄中查找。
因此,當你在終端機中輸入 `python` 時,系統會在以下目錄中找到 Python 程式:
```plaintext
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
並使用這個。
////
一個重要的細節是,虛擬環境路徑會被放在 `PATH` 變數的**開頭**。系統會在找到任何其他可用的 Python **之前**找到它。這樣,當你運行 `python` 時,它會使用**虛擬環境中的** Python,而不是任何其他 `python`(例如,全域環境中的 `python`)。
啟用虛擬環境還會改變其他一些內容,但這是它所做的最重要的事情之一。
## 檢查虛擬環境
當你檢查虛擬環境是否啟動時,例如:
//// tab | Linux, macOS, Windows Bash
<div class="termy">
```console
$ which python
/home/user/code/awesome-project/.venv/bin/python
```
</div>
////
//// tab | Windows PowerShell
<div class="termy">
```console
$ Get-Command python
C:\Users\user\code\awesome-project\.venv\Scripts\python
```
</div>
////
這表示將使用的 `python` 程式是**在虛擬環境中**的那一個。
在 Linux 和 macOS 中使用 `which`,在 Windows PowerShell 中使用 `Get-Command`。
這個指令的運作方式是,它會在 `PATH` 環境變數中搜尋,依序**逐個路徑**查找名為 `python` 的程式。一旦找到,它會**顯示該程式的路徑**。
最重要的是,當你呼叫 `python` 時,將執行的就是這個確切的 "`python`"。
因此,你可以確認是否在正確的虛擬環境中。
/// tip
啟動一個虛擬環境,取得一個 Python,然後**切換到另一個專案**是件很容易的事;
但如果第二個專案**無法正常運作**,那可能是因為你使用了來自其他專案的虛擬環境的、**不正確的 Python**。
因此,檢查正在使用的 `python` 是非常實用的。🤓
///
## 為什麼要停用虛擬環境
例如,你可能正在一個專案 `philosophers-stone` 上工作,**啟動了該虛擬環境**,安裝了套件並使用了該環境,
然後你想要在**另一個專案** `prisoner-of-azkaban` 上工作,
你進入那個專案:
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
```
</div>
如果你不去停用 `philosophers-stone` 的虛擬環境,當你在終端中執行 `python` 時,它會嘗試使用 `philosophers-stone` 中的 Python。
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
$ python main.py
// 匯入 sirius 錯誤,未安裝 😱
Traceback (most recent call last):
File "main.py", line 1, in <module>
import sirius
```
</div>
但如果你停用虛擬環境並啟用 `prisoner-of-askaban` 的新虛擬環境,那麼當你執行 `python` 時,它會使用 `prisoner-of-askaban` 中虛擬環境的 Python。
<div class="termy">
```console
$ cd ~/code/prisoner-of-azkaban
// 你不需要在舊目錄中操作停用,你可以在任何地方操作停用,甚至在切換到另一個專案之後 😎
$ deactivate
// 啟用 prisoner-of-azkaban/.venv 中的虛擬環境 🚀
$ source .venv/bin/activate
// 現在當你執行 python 時,它會在這個虛擬環境中找到已安裝的 sirius 套件 ✨
$ python main.py
I solemnly swear 🐺
```
</div>
## 替代方案
這是一個簡單的指南,幫助你入門並教會你如何理解一切**底層**的原理。
有許多**替代方案**來管理虛擬環境、套件依賴(requirements)、專案。
當你準備好並想要使用一個工具來**管理整個專案**、套件依賴、虛擬環境等,建議你嘗試 <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a>。
`uv` 可以執行許多操作,它可以:
* 為你**安裝 Python**,包括不同的版本
* 為你的專案管理**虛擬環境**
* 安裝**套件**
* 為你的專案管理套件的**依賴和版本**
* 確保你有一個**精確**的套件和版本集合來安裝,包括它們的依賴項,這樣你可以確保專案在生產環境中運行的狀態與開發時在你的電腦上運行的狀態完全相同,這被稱為**鎖定**
* 還有很多其他功能
## 結論
如果你讀過並理解了所有這些,現在**你對虛擬環境的了解已超過許多開發者**。🤓
未來當你為看起來複雜的問題除錯時,了解這些細節很可能會有所幫助,你會知道**它是如何在底層運作的**。😎
+1
View File
@@ -0,0 +1 @@
INHERIT: ../en/mkdocs.yml