帶你瞭解關於FastAPI快速開發Web API專案中的模板和Jinja

2023-04-25 12:00:37
摘要:FastAPI 實際上是為構建 API 和微服務而設計的。它可用於構建使用 Jinja 提供 HTML 服務的 Web 應用程式。

本文分享自華為雲社群《FastAPI 快速開發 Web API 專案: 模板和 Jinja 介紹》,作者:宇宙之一粟。

什麼是 Jinja

模板是全棧 Web 開發的重要組成部分。使用 Jinja,您可以構建豐富的模板,為您的 Python Web 應用程式的前端提供支援。

Jinja 是一個用 Python 編寫的模板引擎,旨在幫助 API 響應的渲染過程。在每種模板語言中,都有變數被替換為實際傳遞給它們的值,當模板被渲染時,有控制模板邏輯的標籤。

安裝 jinja2:

pipenv install jinja2

安裝成功後:

Jinja 模板只是一個文字檔案。 Jinja 可以生成任何基於文字的格式(HTML、XML、CSV、LaTeX 等)。 Jinja 模板不需要有特定的擴充套件名:.html、.xml 或任何其他擴充套件名都可以。

關於模版的擴充套件名:任何檔案都可以作為模板載入,無論副檔名如何。新增 .jinja 擴充套件名,如 user.html.jinja 可能會使某些 IDE 或編輯器外掛更容易,但這不是必需的。自動跳脫可以基於副檔名應用,因此在這種情況下您需要考慮額外的字尾。
識別模板的另一個很好的啟發式方法是它們位於模板 templates 資料夾中,而不管擴充套件名是什麼。這是專案的常見佈局。

Jinja 模板引擎使用花括號 {} 來區分其表示式和語法與常規 HTML、文字和模板檔案中的任何其他變數。{{}} 語法稱為變數塊。{% %} 語法包含控制結構,如 if/else 、迴圈和宏。Jinja 模板語言中使用的三種常見語法塊包括以下內容:

  • {% ... %}:這種語法用於控制結構等語句。
  • {{ todo.item }}:這個語法用於列印出傳遞給它的表示式的值。
  • {# Test #}: 這種語法在寫評論時使用,不在網頁上顯示。

Jinja2 是一種流行的模板語言,被 Flask、Bottle、Pelican 使用,也可被 Django 使用。

渲染第一個 Jinja 模板

匯入 Jinja 後,您可以繼續載入和渲染您的第一個模板:

>>> import jinja2
>>> environment = jinja2.Environment()
>>> template = environment.from_string("Hello, {{ name }}!") 
>>> template.render(name="Yuzhou1su")
'Hello, Yuzhou1su!'
>>>

Jinja 的核心元件是 Environment() 類。在此範例中,您建立了一個不帶任何引數的 Jinja 環境。稍後您將更改 Environment 的引數以自定義您的環境。在這裡,您正在建立一個普通環境,您可以在其中載入字串 Hello, {{ name }}! 作為模板。

這個例子顯示了你在使用 Jinja 時通常會執行的兩個重要步驟:

  1. 載入模板:載入包含預留位置變數的源。預設情況下,它們包含在一對大括號 {{ }} 中。
  2. 渲染模板:用內容填充預留位置。您可以提供字典或關鍵字引數作為上下文。在本例中,您已經填充了預留位置,因此 Hello, Yuzhou1su! 作為輸出。

使用外部檔案作為模板

與上述方式同理,我們可以使用外部檔案作為我們的模版來源,在我們的專案中建立一個新資料夾。在工作目錄中,建立一個名為 templates/ 的資料夾。

然後,您可以在 「template」 目錄中建立 index.html 模板檔案,並使用 Jinja2 語法來呈現它們。例如,在template/index.html 中寫入如下內容:

<!DOCTYPE html>
<html>
 <head>
 <title>Welcome</title>
 <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
 </head>
 <body>
 <h1>Hello, {{ name }}</h1>
 </body>
</html>

然後回到我們的 main.py 中:

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
@app.get("/{name}")
async def home(request: Request, name: str):
 return templates.TemplateResponse("index.html", {
 "request": request,
 "name": name
 })

整個檔案的目錄結構如下:

啟動 FastAPI 服務 uvicorn main:app --reload --port 8888, 然後另外開啟一個終端,執行 curl 127.0.0.1:8888/Yuzhou1su 命令,可以看到如下 name 被渲染出來的結果:

通過瀏覽器存取這個 http://127.0.0.1:8888/Yuzhou1su,還能看到 css 渲染的顏色:

Jinja 模板變數可以是任何 Python 型別或物件,只要它們可以轉換為字串。可以將模型、列表或字典型別傳遞到模板中,並通過將這些屬性放置在先前列出的第二個塊中來顯示其屬性。在下一節中,我們將看一下過濾器。過濾器是每個模板引擎的重要組成部分,在 Jinja 中,過濾器使我們能夠執行某些函數,例如從列表中連線值和檢索物件的長度,等等。Jinja 中常用的功能:變數、過濾器、if 語句、迴圈、宏和模板繼承。

變數

模板變數由傳遞給模板的上下文字典定義。

在模板中,只要應用程式傳遞了變數,您就可以隨意操作這些變數。變數可能還具有您可以存取的屬性或元素。變數具有哪些屬性取決於提供該變數的應用程式。

除了標準的 Python __getitem__ 「下標」語法( [] )之外,您還可以使用點(. )來存取變數的屬性。

以下行執行相同的操作:

{{ foo.bar }}
{{ foo['bar'] }}

Filters

儘管 Python 和 Jinja 的語法非常相似,但是像連線字串、將字串的第一個字元設定為大寫等修改操作不能使用Python 的語法在 Jinja 中完成。因此,為了執行這樣的修改操作,我們在 Jinja 中使用過濾器。

變數可以被過濾器修改。過濾器與變數用管道符號(|)分隔,並且可以在括號中包含可選引數。可以連結多個過濾器。一個過濾器的輸出應用於下一個。過濾器的定義格式如下:

{{ variable | filter_name(*args) }}

不加引數的過濾器:

{{ variable | filter_name }}
{{ name|striptags|title }}

default 過濾器: 如果該值未定義,它將返回傳遞的預設值,否則返回變數的值:

{{ my_variable | default('my_variable is not defined') }}

escape 過濾器: 這個過濾器用於渲染原始 HTML 輸出:將字串 s 中的字元 & < > ' 」 轉換為 HTML 安全序列。如果您需要在 HTML 中顯示可能包含此類字元的文字,請使用此選項。將返回值標記為標記字串。

{{ "<title>Todo Application</title>" | escape }}
<title>Todo Application</title>

型別轉換過濾器: 這些過濾器包括 int 和 float 過濾器,用於從一種資料型別轉換到另一種資料型別:

{{ 3.142 | int }}
3
{{ 20 | float }}
20.0

join 過濾器:join(*value*, *d=u''* , *attribute=None*)返回一個字串,它是序列中字串的串聯。元素之間的分隔符預設為空字串,您可以使用可選引數定義它:

{{ [1, 2, 3] | join('|') }}
 -> 1|2|3
{{ [1, 2, 3] | join }}
 -> 123

也可以連線物件的某些屬性:

{{ users|join(', ', attribute='username') }}

長度 filter: 這個過濾器返回一個序列或集合的長度,它的作用與 Python 中 len() 函數的作用相同:

Todo count: {{ todos | length }}
Todo count: 4

if 條件

Jinja 中 if 語句的用法與 Python 中的用法類似。在 {% %} 控制塊中使用。讓我們看一個例子:

{% if todos %}
<ul>
{% for todo in todos %}
 <li>{{ todo.name|e }}</li>
{% endfor %}
</ul>
{% endif %}

Loop 條件

我們也可以在Jinja中對變數進行迭代。這可以是一個列表或一個一般的函數、 比如說下面這個,例如

{% for todo in todos %}
 <li>{{ todo.name|e }}</li>
{% endfor %}

你可以在 for 迴圈中存取特殊的變數,比如 loop.index ,它給出了當前迭代的索引。

宏可與常規程式語言中的函數相媲美。它們有助於將常用的習語放入可重用的函數中,以免重複自己(「DRY」 原則)。

{% macro input(name, value='', type='text', size=20) %}
 <div class="form">
 <input type="{{ type }}" name="{{ name }}"
            value="{{ value|escape }}" size="{{ size }}">
 </div>
{% endmacro %}

現在,為了在你的表單中快速建立一個輸入,呼叫了這個宏:

{{ input('item') }}

渲染完成後,將會返回:

 <div class="form">
 <input type="text" name="item" value="" size="20" />
 </div>

FastAPI 中的 Jinja

FastAPI 實際上是為構建 API 和微服務而設計的。它可用於構建使用 Jinja 提供 HTML 服務的 Web 應用程式,但這並不是它真正優化的目的。

如果您想構建一個在伺服器上呈現大量 HTML 的大型網站,Django 可能是更好的選擇。

但是,如果您正在使用 React、Angular 或 Vue 等前端框架構建現代網站,那麼從 FastAPI 獲取資料是一個不錯的選擇。

參考連結:

  • Templates
  • The Ultimate FastAPI Tutorial Part 6 - Serving HTML with Jinja Templates
  • Simple ToDo App in FastAPI with Jinja2 Template
  • Primer on Jinja Templating
  • Template Designer Documentation

 

點選關注,第一時間瞭解華為雲新鮮技術~