範本¶
作為一個網頁框架,Django 需要一種方便的方式來動態生成 HTML。最常見的方法是依賴範本。範本包含所需 HTML 輸出的靜態部分,以及一些描述如何插入動態內容的特殊語法。如需使用範本建立 HTML 頁面的實務範例,請參閱教學 3。
可以使用一個或多個範本引擎(或者如果您不使用範本,則甚至可以是零個)來設定 Django 專案。Django 為其自己的範本系統(創造性地稱為 Django 範本語言 (DTL))和流行的替代方案 Jinja2 提供了內建後端。其他範本語言的後端可能可從第三方取得。您也可以編寫自己的自訂後端,請參閱自訂範本後端。
Django 定義了一個標準 API,用於載入和渲染範本,而與後端無關。載入包括尋找給定識別碼的範本並對其進行預處理,通常是將其編譯為記憶體中的表示形式。渲染是指使用上下文資料來內插範本並傳回結果字串。
Django 範本語言是 Django 自己的範本系統。在 Django 1.8 之前,它是唯一可用的內建選項。它是一個不錯的範本庫,即使它相當固執己見並且有一些特殊的怪癖。如果您沒有迫切的理由選擇其他後端,您應該使用 DTL,尤其是當您編寫可外掛的應用程式並且打算發佈範本時。包含範本的 Django contrib 應用程式,例如django.contrib.admin,使用 DTL。
由於歷史原因,對範本引擎的一般支援和 Django 範本語言的實作都位於django.template
命名空間中。
警告
範本系統對於不受信任的範本作者來說並不安全。例如,網站不應允許其使用者提供自己的範本,因為範本作者可以執行 XSS 攻擊和存取可能包含敏感資訊的範本變數的屬性等操作。
Django 範本語言¶
語法¶
關於本節
這是 Django 範本語言語法的概述。如需詳細資訊,請參閱語言語法參考。
Django 範本是一個文字文件或使用 Django 範本語言標記的 Python 字串。某些結構會被範本引擎識別和解釋。主要的是變數和標籤。
範本使用內容來渲染。渲染會將變數替換為其值(這些值在內容中查找),並執行標籤。其他所有內容都會按原樣輸出。
Django 範本語言的語法包含四種結構。
變數¶
變數會從內容輸出一個值,該內容是一個類似字典的物件,將鍵對應到值。
變數用 {{
和 }}
包圍,如下所示
My first name is {{ first_name }}. My last name is {{ last_name }}.
使用 {'first_name': 'John', 'last_name': 'Doe'}
的內容,此範本會渲染為
My first name is John. My last name is Doe.
字典查找、屬性查找和清單索引查找使用點表示法實作
{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}
如果變數解析為可呼叫的變數,則範本系統會呼叫它,但不帶引數,並使用其結果而不是可呼叫的變數。
篩選器¶
篩選器會轉換變數和標籤引數的值。
它們看起來像這樣
{{ django|title }}
使用 {'django': 'the web framework for perfectionists with deadlines'}
的內容,此範本會渲染為
The Web Framework For Perfectionists With Deadlines
某些篩選器會採用引數
{{ my_date|date:"Y-m-d" }}
有一個內建篩選器的參考,以及撰寫自訂篩選器的指示。
註解¶
註解看起來像這樣
{# this won't be rendered #}
{% comment %}
標籤提供多行註解。
組件¶
關於本節
這是 Django 範本語言 API 的概述。如需詳細資訊,請參閱API 參考。
引擎¶
django.template.Engine
封裝了 Django 範本系統的執行個體。直接實例化 Engine
的主要原因是,在 Django 專案之外使用 Django 範本語言。
django.template.backends.django.DjangoTemplates
是一個輕型包裝函式,可將 django.template.Engine
適應 Django 的範本後端 API。
範本¶
django.template.Template
代表已編譯的範本。範本是透過 Engine.get_template()
或 Engine.from_string()
取得的。
同樣地,django.template.backends.django.Template
是一個輕型包裝函式,可將 django.template.Template
適應通用範本 API。
內容¶
django.template.Context
除了內容資料外,還會保留一些中繼資料。它會傳遞到 Template.render()
,以用於渲染範本。
django.template.RequestContext
是 Context
的子類別,它會儲存目前的 HttpRequest
並執行範本內容處理器。
通用 API 沒有等效的概念。內容資料會以純 dict
的形式傳遞,目前的 HttpRequest
會在需要時單獨傳遞。
載入器¶
樣板載入器負責尋找樣板、載入它們並返回 Template
物件。
Context processors¶
Context processors 是接收當前 HttpRequest
作為引數的函式,並回傳一個 dict
的資料,該資料將被加入到渲染上下文(rendering context)。
它們的主要用途是在不重複程式碼的情況下,將所有樣板共用的通用資料加入到上下文中。
Django 提供了許多內建的 context processors,您也可以實作自己的額外 context processors。
樣板引擎的支援¶
組態設定¶
樣板引擎是透過 TEMPLATES
設定來配置的。它是一個組態設定的列表,每個引擎一個設定。預設值為空。由 startproject
命令產生的 settings.py
定義了一個更有用的值。
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
# ... some options here ...
},
},
]
BACKEND
是一個指向實作 Django 樣板後端 API 的樣板引擎類別的 Python 點狀路徑。內建的後端是 django.template.backends.django.DjangoTemplates
和 django.template.backends.jinja2.Jinja2
。
由於大多數引擎是從檔案載入樣板,因此每個引擎的頂層組態都包含兩個常見的設定。
DIRS
定義了一個目錄列表,引擎應該按照搜尋順序在這些目錄中尋找樣板來源檔案。APP_DIRS
設定是否讓引擎在已安裝應用程式內尋找樣板。每個後端都會為應用程式內應該儲存其樣板的子目錄定義一個慣用名稱。
雖然不常見,但可以使用不同的選項配置同一個後端的幾個實例。在這種情況下,您應該為每個引擎定義一個唯一的 NAME
。
OPTIONS
包含後端特定的設定。
用法¶
django.template.loader
模組定義了兩個用於載入樣板的函式。
- get_template(template_name, using=None)[來源]¶
這個函式載入指定名稱的樣板,並返回一個
Template
物件。回傳值的確切類型取決於載入樣板的後端。每個後端都有自己的
Template
類別。get_template()
會依序嘗試每個樣板引擎,直到其中一個成功為止。如果找不到樣板,它會引發TemplateDoesNotExist
。如果找到樣板但包含無效語法,它會引發TemplateSyntaxError
。樣板的搜尋和載入方式取決於每個引擎的後端和組態。
如果您想要將搜尋範圍限制在特定的樣板引擎,請在
using
引數中傳遞引擎的NAME
。
- select_template(template_name_list, using=None)[來源]¶
select_template()
和get_template()
非常相似,只是它接受一個樣板名稱的列表。它會依序嘗試每個名稱,並返回第一個存在的樣板。
如果載入樣板失敗,可能會引發以下在 django.template
中定義的兩個例外狀況:
- exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[來源]¶
當找不到樣板時,會引發此例外。它接受以下選用引數,以便在除錯頁面上填入樣板剖析報告。
backend
產生此例外的樣板後端實例。
tried
在尋找樣板時嘗試過的來源列表。格式為包含
(origin, status)
的元組列表,其中origin
是一個類似來源 的物件,而status
是一個表示找不到樣板的原因的字串。chain
嘗試載入樣板時引發的中繼
TemplateDoesNotExist
例外列表。此列表被諸如get_template()
等函式使用,這些函式會嘗試從多個引擎載入給定的樣板。
由 get_template()
和 select_template()
返回的 Template
物件必須提供一個具有以下簽章的 render()
方法:
- Template.render(context=None, request=None)¶
使用給定的上下文渲染此樣板。
如果提供了
context
,則它必須是一個dict
。如果沒有提供,引擎將使用空上下文渲染樣板。如果提供了
request
,則它必須是一個HttpRequest
。然後,引擎必須將其以及 CSRF token 提供給樣板。如何實現這一點取決於每個後端。
以下是一個搜尋演算法的範例。在此範例中,TEMPLATES
設定為:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
"/home/html/example.com",
"/home/html/default",
],
},
{
"BACKEND": "django.template.backends.jinja2.Jinja2",
"DIRS": [
"/home/html/jinja2",
],
},
]
如果您呼叫 get_template('story_detail.html')
,以下是 Django 將依序搜尋的檔案:
/home/html/example.com/story_detail.html
('django'
引擎)/home/html/default/story_detail.html
('django'
引擎)/home/html/jinja2/story_detail.html
('jinja2'
引擎)
如果您呼叫 select_template(['story_253_detail.html', 'story_detail.html'])
,以下是 Django 將搜尋的內容:
/home/html/example.com/story_253_detail.html
('django'
引擎)/home/html/default/story_253_detail.html
('django'
引擎)/home/html/jinja2/story_253_detail.html
('jinja2'
引擎)/home/html/example.com/story_detail.html
('django'
引擎)/home/html/default/story_detail.html
('django'
引擎)/home/html/jinja2/story_detail.html
('jinja2'
引擎)
當 Django 找到存在的樣板時,它會停止搜尋。
使用 django.template.loader.select_template()
以獲得更大的彈性。
您可以使用 select_template()
進行彈性的樣板載入。例如,如果您寫了一篇新聞報導,並希望某些報導使用自訂樣板,可以使用類似 select_template(['story_%s_detail.html' % story.id, 'story_detail.html'])
的程式碼。這樣您就可以為個別報導使用自訂樣板,並為沒有自訂樣板的報導使用備用樣板。
在每個包含樣板的目錄中,將樣板組織在子目錄中是可行且較佳的做法。慣例是為每個 Django 應用程式建立一個子目錄,並在這些子目錄中根據需要建立更多子目錄。
為了您自己好,請這樣做。將所有樣板儲存在單一目錄的根目錄層級會變得雜亂無章。
若要載入子目錄中的樣板,請使用斜線,如下所示:
get_template("news/story_detail.html")
使用與上述相同的 TEMPLATES
選項,這將嘗試載入以下樣板:
/home/html/example.com/news/story_detail.html
('django'
引擎 )/home/html/default/news/story_detail.html
('django'
引擎 )/home/html/jinja2/news/story_detail.html
('jinja2'
引擎 )
此外,為了減少重複載入和渲染樣板的繁瑣,Django 提供了一個快捷函式來自動化此過程。
- render_to_string(template_name, context=None, request=None, using=None)[原始碼]¶
render_to_string()
載入樣板的方式與get_template()
相同,並立即呼叫其render()
方法。它接受以下引數。template_name
要載入和渲染的樣板名稱。如果它是樣板名稱的清單,Django 會使用
select_template()
而不是get_template()
來尋找樣板。context
一個
dict
,用作渲染樣板的內容。request
一個可選的
HttpRequest
,在樣板的渲染過程中可用。using
一個可選的樣板引擎
NAME
。樣板的搜尋將僅限於該引擎。
使用範例
from django.template.loader import render_to_string rendered = render_to_string("my_template.html", {"foo": "bar"})
另請參閱 render()
快捷方式,它會呼叫 render_to_string()
,並將結果饋入 HttpResponse
中,適合從檢視中傳回。
最後,您可以直接使用已設定的引擎
內建後端¶
將 BACKEND
設定為 'django.template.backends.django.DjangoTemplates'
以設定 Django 樣板引擎。
當 APP_DIRS
為 True
時,DjangoTemplates
引擎會在已安裝應用程式的 templates
子目錄中尋找樣板。此通用名稱保留用於向後相容性。
DjangoTemplates
引擎接受以下 OPTIONS
:
'autoescape'
:一個布林值,控制是否啟用 HTML 自動跳脫。預設值為
True
。警告
僅在您渲染非 HTML 樣板時,才將其設定為
False
!'context_processors'
:一個虛線 Python 路徑清單,指向用於在樣板使用請求渲染時,填入內容的可呼叫物件。這些可呼叫物件會將請求物件作為引數,並傳回要合併到內容中的項目dict
。預設值為空清單。
如需更多資訊,請參閱
RequestContext
。'debug'
:一個布林值,可開啟/關閉樣板除錯模式。如果它是True
,則精美的錯誤頁面將顯示在樣板渲染期間引發的任何例外狀況的詳細報告。此報告包含具有相應行突出顯示的相關樣板片段。預設值為
DEBUG
設定的值。'loaders'
:一個虛線 Python 路徑清單,指向樣板載入器類別。每個Loader
類別都知道如何從特定來源匯入樣板。或者,可以使用元組代替字串。元組中的第一個項目應該是Loader
類別名稱,後續項目會傳遞給初始化期間的Loader
。如需詳細資訊,請參閱 載入器類型。
'string_if_invalid'
:當變數無效時(例如拼寫錯誤),樣板系統應使用的字串輸出。預設值為空字串。
如需詳細資訊,請參閱 如何處理無效變數。
'file_charset'
:用於讀取磁碟上的樣板檔案的字元集。預設值為
'utf-8'
。'libraries'
:一個標籤字典,以及要向樣板引擎註冊的樣板標籤模組的虛線 Python 路徑。這可以用於新增程式庫或為現有程式庫提供替代標籤。例如:OPTIONS = { "libraries": { "myapp_tags": "path.to.myapp.tags", "admin.urls": "django.contrib.admin.templatetags.admin_urls", }, }
可以透過將對應的字典鍵傳遞給
{% load %}
標籤來載入程式庫。'builtins'
:一個虛線 Python 路徑清單,指向要新增到 內建模組 的樣板標籤模組。例如:OPTIONS = { "builtins": ["myapp.builtins"], }
可以使用內建程式庫中的標籤和篩選器,而無需先呼叫
{% load %}
標籤。
需要安裝 Jinja2
$ python -m pip install Jinja2
...\> py -m pip install Jinja2
將 BACKEND
設定為 'django.template.backends.jinja2.Jinja2'
以設定 Jinja2 引擎。
當 APP_DIRS
設定為 True
時,Jinja2
引擎會在已安裝應用程式的 jinja2
子目錄中尋找範本。
OPTIONS
中最重要的條目是 'environment'
。它是一個以點分隔的 Python 路徑,指向一個返回 Jinja2 環境的可調用物件。預設值為 'jinja2.Environment'
。Django 會調用該可調用物件,並將其他選項作為關鍵字引數傳遞。此外,Django 還為一些選項增加了與 Jinja2 不同的預設值。
'autoescape'
:True
'auto_reload'
:settings.DEBUG
'undefined'
:DebugUndefined if settings.DEBUG else Undefined
Jinja2
引擎也接受以下 OPTIONS
'context_processors'
:一個虛線 Python 路徑清單,指向用於在樣板使用請求渲染時,填入內容的可呼叫物件。這些可呼叫物件會將請求物件作為引數,並傳回要合併到內容中的項目dict
。預設值為空清單。
不建議將上下文處理器與 Jinja2 範本一起使用。
上下文處理器在 Django 範本中很有用,因為 Django 範本不支援使用引數調用函式。由於 Jinja2 沒有此限制,因此建議將您將用作上下文處理器的函式放入可供範本使用的全域變數中,方法是使用如下所述的
jinja2.Environment
。然後,您可以在範本中調用該函式。{{ function(request) }}
一些 Django 範本上下文處理器會返回一個固定值。對於 Jinja2 範本,由於您可以直接在
jinja2.Environment
中新增常數,因此不需要此間接層。為 Jinja2 新增上下文處理器的原始用例涉及:
執行依賴於請求的昂貴計算。
每個範本都需要結果。
在每個範本中多次使用結果。
除非滿足所有這些條件,否則將函式傳遞給範本更符合 Jinja2 的設計理念。
預設配置盡可能保持最小化。如果範本是使用請求呈現的(例如,使用 render()
時),Jinja2
後端會將全域變數 request
、csrf_input
和 csrf_token
新增到上下文中。除此之外,此後端不會建立 Django 風格的環境。它不知道 Django 的篩選器和標籤。為了使用 Django 特定的 API,您必須將它們配置到環境中。
例如,您可以建立具有以下內容的 myproject/jinja2.py
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update(
{
"static": static,
"url": reverse,
}
)
return env
並將 'environment'
選項設定為 'myproject.jinja2.environment'
。
然後,您可以在 Jinja2 範本中使用以下結構
<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">
<a href="{{ url('admin:index') }}">Administration</a>
標籤和篩選器的概念同時存在於 Django 範本語言和 Jinja2 中,但它們的使用方式不同。由於 Jinja2 支援將引數傳遞給範本中的可調用物件,因此許多在 Django 範本中需要範本標籤或篩選器的功能,可以通過調用 Jinja2 範本中的函式來實現,如以上範例所示。Jinja2 的全域命名空間消除了對範本上下文處理器的需求。Django 範本語言沒有與 Jinja2 測試等效的功能。