Django 樣板語言:給 Python 程式設計師¶
本文從技術角度解釋 Django 樣板系統 – 其運作方式以及如何擴展它。如果您正在尋找有關語言語法的參考資料,請參閱 Django 樣板語言。
本文假設您了解樣板、上下文、變數、標籤和渲染。如果您不熟悉這些概念,請從 Django 樣板語言簡介 開始。
概觀¶
在 Python 中使用樣板系統是一個三步驟流程
Django 專案通常依賴於這些步驟的 高階、與後端無關的 API,而不是樣板系統的較低階 API。
對於
TEMPLATES
設定中的每個DjangoTemplates
後端,Django 都會實例化一個Engine
。DjangoTemplates
包裝Engine
並將其調整為通用的樣板後端 API。django.template.loader
模組提供諸如get_template()
等函式來載入樣板。它們會傳回一個django.template.backends.django.Template
,它會包裝實際的django.template.Template
。在前一個步驟中取得的
Template
有一個render()
方法,它會將上下文和可能的請求編組到一個Context
,並將渲染委派給底層的Template
。
設定引擎¶
如果您正在使用 DjangoTemplates
後端,那麼這可能不是您要找的文件。使用該後端的 engine
屬性可以存取下面描述的 Engine
類別的實例,並且下面提到的任何屬性預設值都會被 DjangoTemplates
傳遞的值覆寫。
- class Engine(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid='', file_charset='utf-8', libraries=None, builtins=None, autoescape=True)[原始碼]¶
在實例化
Engine
時,所有引數都必須作為關鍵字引數傳遞dirs
是一個目錄列表,引擎應在其中尋找樣板原始檔。它用於設定filesystem.Loader
。預設為空列表。
app_dirs
只會影響loaders
的預設值。請參閱下文。預設為
False
。autoescape
控制是否啟用 HTML 自動跳脫。預設為
True
。警告
只有在您渲染非 HTML 樣板時,才將其設定為
False
!context_processors
是一個以點分隔的 Python 路徑列表,指向可用於在以請求渲染樣板時填入上下文的可呼叫物件。這些可呼叫物件會接收一個請求物件作為其引數,並傳回一個dict
,其中包含要合併到上下文中的項目。預設為空列表。
有關更多資訊,請參閱
RequestContext
。debug
是一個布林值,用於開啟/關閉樣板偵錯模式。如果它是True
,樣板引擎將儲存額外的偵錯資訊,這些資訊可用於顯示在樣板渲染期間引發的任何例外狀況的詳細報告。預設為
False
。loaders
是一個樣板載入器類別列表,指定為字串。每個Loader
類別都知道如何從特定來源匯入樣板。或者,可以使用元組而不是字串。元組中的第一個項目應該是Loader
類別名稱,後續項目將在初始化期間傳遞給Loader
。預設為包含的列表
'django.template.loaders.filesystem.Loader'
僅當
app_dirs
為True
時,才為'django.template.loaders.app_directories.Loader'
。
然後,這些載入器會被包裝在
django.template.loaders.cached.Loader
中。有關詳細資訊,請參閱 載入器類型。
string_if_invalid
是樣板系統應該用於無效(例如,拼寫錯誤)變數的輸出(作為字串)。預設為空字串。
有關詳細資訊,請參閱 如何處理無效的變數。
file_charset
是用於讀取磁碟上樣板檔案的字元集。預設為
'utf-8'
。'libraries'
:一個標籤和樣板標籤模組的點分隔 Python 路徑的字典,用於向樣板引擎註冊。這用於新增新的程式庫或為現有的程式庫提供替代標籤。例如Engine( libraries={ "myapp_tags": "path.to.myapp.tags", "admin.urls": "django.contrib.admin.templatetags.admin_urls", }, )
可以透過將相應的字典鍵傳遞給
{% load %}
標籤來載入程式庫。'builtins'
:一個以點分隔的 Python 路徑列表,指向要新增到 內建 的樣板標籤模組。例如Engine( builtins=["myapp.builtins"], )
可以使用內建程式庫中的標籤和篩選器,而無需先呼叫
{% load %}
標籤。
- static Engine.get_default()[原始碼]¶
從第一個已設定的
Engine
引擎回傳底層的Engine
。如果沒有設定任何引擎,則會引發ImproperlyConfigured
錯誤。這是為了保留依賴全域可用、隱式設定引擎的 API 所必需的。強烈建議不要用於其他用途。
- Engine.select_template(template_name_list)[原始碼]¶
類似於
get_template()
,但它接受名稱列表並回傳找到的第一個樣板。
載入樣板¶
建立 Template
的建議方式是呼叫 Engine
的工廠方法:get_template()
、select_template()
和 from_string()
。
在 Django 專案中,如果 TEMPLATES
設定定義了 DjangoTemplates
引擎,則可以直接實例化一個 Template
。如果定義了多個 DjangoTemplates
引擎,則將使用第一個。
- class Template[原始碼]¶
此類別位於
django.template.Template
。建構函式接受一個參數 — 原始樣板程式碼from django.template import Template template = Template("My name is {{ my_name }}.")
幕後機制
系統只會解析您的原始樣板程式碼一次 – 當您建立 Template
物件時。從那時起,它會在內部儲存為效能考量的樹狀結構。
即使解析本身也相當快速。大多數解析是透過對單個、簡短的正規表示式進行單次呼叫來完成的。
呈現 Context¶
一旦您有一個已編譯的 Template
物件,您就可以使用它來呈現 Context。您可以重複使用相同的樣板,以不同的 Context 多次呈現它。
- class Context(dict_=None, autoescape=True, use_l10n=None, use_tz=None)[原始碼]¶
django.template.Context
的建構函式接受一個可選參數 — 將變數名稱對應到變數值的字典。也可以指定三個可選的關鍵字引數
autoescape
控制是否啟用 HTML 自動跳脫。預設為
True
。警告
只有在您渲染非 HTML 樣板時,才將其設定為
False
!use_l10n
覆寫預設是否會本地化值。如果設定為True
,數字和日期將根據地區設定格式化。預設值為
None
。有關詳細資訊,請參閱 在樣板中控制本地化。
use_tz
覆寫日期在樣板中呈現時是否轉換為當地時間。如果設定為True
,所有日期都將使用當地時區呈現。這優先於USE_TZ
。預設值為
None
。有關詳細資訊,請參閱 樣板中具時區意識的輸出。
有關使用範例,請參閱下方的 使用 Context 物件。
- Template.render(context)[原始碼]¶
呼叫
Template
物件的render()
方法,並傳入一個Context
來「填入」樣板>>> from django.template import Context, Template >>> template = Template("My name is {{ my_name }}.") >>> context = Context({"my_name": "Adrian"}) >>> template.render(context) "My name is Adrian." >>> context = Context({"my_name": "Dolores"}) >>> template.render(context) "My name is Dolores."
變數和查詢¶
變數名稱必須包含任何字母 (A-Z)、任何數字 (0-9)、底線(但它們不得以底線開頭)或點號。
點號在樣板呈現中具有特殊含義。變數名稱中的點號表示查詢。具體而言,當樣板系統在變數名稱中遇到點號時,它會依此順序嘗試以下查詢:
字典查詢。範例:
foo["bar"]
屬性查詢。範例:
foo.bar
清單索引查詢。範例:
foo[bar]
請注意,如果樣板 Context 中存在變數 “bar”,則在像 {{ foo.bar }}
的樣板運算式中,「bar」會被解讀為文字字串,而不是使用變數 “bar” 的值。
樣板系統會使用第一個有效的查詢類型。它是短路邏輯。以下是一些範例:
>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."
>>> class PersonClass:
... pass
...
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."
如果變數的任何部分是可呼叫的,則樣板系統會嘗試呼叫它。範例:
>>> class PersonClass2:
... def name(self):
... return "Samantha"
...
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
可呼叫變數比只需要直接查詢的變數稍微複雜一些。以下是一些需要記住的事項:
如果變數在呼叫時引發例外,則該例外將會傳播,除非該例外具有一個屬性
silent_variable_failure
,其值為True
。如果例外確實具有一個silent_variable_failure
屬性,其值為True
,則變數將呈現為引擎string_if_invalid
設定選項的值(預設為空字串)。範例:>>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError("foo") ... >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(Exception): ... silent_variable_failure = True ... >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError ... >>> p = PersonClass4() >>> t.render(Context({"person": p})) "My name is ."
請注意,
django.core.exceptions.ObjectDoesNotExist
是所有 Django 資料庫 APIDoesNotExist
例外的基底類別,它具有silent_variable_failure = True
。因此,如果您將 Django 樣板與 Django 模型物件一起使用,任何DoesNotExist
例外都會靜默失敗。只有在變數沒有需要的引數時才能呼叫它。否則,系統將回傳引擎的
string_if_invalid
選項的值。
呼叫某些變數可能會產生副作用,並且允許樣板系統存取它們既愚蠢又會產生安全漏洞。
一個很好的例子是每個 Django 模型物件上的
delete()
方法。不應該允許樣板系統執行類似以下的操作:I will now delete this valuable data. {{ data.delete }}
為了避免這種情況,請在可呼叫變數上設定
alters_data
屬性。如果變數設定了alters_data=True
,範本系統就不會呼叫該變數,而是無條件地將變數替換為string_if_invalid
。Django 模型物件上動態產生的delete()
和save()
方法會自動設定alters_data=True
。範例:def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
有時,您可能因為其他原因想要關閉此功能,並告知範本系統無論如何都不要呼叫變數。若要這麼做,請在可呼叫變數上設定一個
do_not_call_in_templates
屬性,值為True
。這樣範本系統就會像對待不可呼叫的變數一樣(例如,讓您可以存取該可呼叫變數的屬性)。
如何處理無效變數¶
一般而言,如果變數不存在,範本系統會插入引擎的 string_if_invalid
設定選項的值,預設值為 ''
(空字串)。
只有當 string_if_invalid
設定為 ''
(空字串)時,套用至無效變數的篩選器才會被套用。如果 string_if_invalid
設定為任何其他值,變數篩選器將會被忽略。
對於 if
、 for
和 regroup
範本標籤,此行為略有不同。如果將無效變數提供給這些範本標籤之一,該變數將會被視為 None
。篩選器會始終套用至這些範本標籤內的無效變數。
如果 string_if_invalid
包含 '%s'
,格式標記將會被替換為無效變數的名稱。
僅限於除錯目的!
雖然 string_if_invalid
可以是一個有用的除錯工具,但將其作為「開發預設值」開啟並不是一個好主意。
許多範本,包括 Django 的一些範本,都依賴於範本系統在遇到不存在的變數時保持靜默。如果您將 string_if_invalid
的值設為 ''
以外的值,您將會在這些範本和網站上遇到渲染問題。
一般而言,string_if_invalid
應該只在除錯特定的範本問題時才啟用,並在除錯完成後清除。
內建變數¶
每個內容都包含 True
、False
和 None
。正如您所預期的,這些變數會解析為相應的 Python 物件。
字串常值的限制¶
Django 的範本語言無法跳脫其自身語法所使用的字元。例如,如果您需要輸出像 {%
和 %}
這樣的字元序列,則需要使用 templatetag
標籤。
如果您想要在範本篩選器或標籤引數中包含這些序列,也會出現類似的問題。例如,當剖析區塊標籤時,Django 的範本剖析器會在 {%
之後尋找第一次出現的 %}
。這會阻止使用 "%}"
作為字串常值。例如,以下運算式會引發 TemplateSyntaxError
{% include "template.html" tvar="Some string literal with %} in it." %}
{% with tvar="Some string literal with %} in it." %}{% endwith %}
在篩選器引數中使用保留序列也會觸發相同的問題
{{ some.variable|default:"}}" }}
如果您需要使用包含這些序列的字串,請將它們儲存在範本變數中,或使用自訂範本標籤或篩選器來解決這個限制。
使用 Context
物件¶
大多數情況下,您會透過將完整填入的字典傳遞給 Context()
來實例化 Context
物件。但是,您也可以在使用標準字典語法實例化 Context
物件後,從中新增和刪除項目
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c["foo"]
'bar'
>>> del c["foo"]
>>> c["foo"]
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c["newvariable"] = "hello"
>>> c["newvariable"]
'hello'
- Context.get(key, otherwise=None)¶
如果
key
在內容中,則傳回key
的值,否則傳回otherwise
。
- Context.setdefault(key, default=None)¶
如果
key
在內容中,則傳回其值。否則,插入key
,值為default
,並傳回default
。
- Context.pop()¶
- Context.push()¶
Context
物件是一個堆疊。也就是說,您可以 push()
和 pop()
它。如果您 pop()
過多,它會引發 django.template.ContextPopException
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.push()
{}
>>> c["foo"] = "second level"
>>> c["foo"]
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c["foo"]
'first level'
>>> c["foo"] = "overwritten"
>>> c["foo"]
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException
您也可以使用 push()
作為內容管理器,以確保呼叫對應的 pop()
。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push():
... c["foo"] = "second level"
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
傳遞給 push()
的所有引數都會傳遞給用於建構新內容層級的 dict
建構函式。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.push(foo="second level"):
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
除了 push()
和 pop()
之外,Context
物件還定義了 update()
方法。它的作用類似於 push()
,但是它會接收一個字典作為引數,並將該字典推送至堆疊上,而不是一個空字典。
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.update({"foo": "updated"})
{'foo': 'updated'}
>>> c["foo"]
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c["foo"]
'first level'
和 push()
一樣,您可以使用 update()
作為內容管理器,以確保呼叫對應的 pop()
。
>>> c = Context()
>>> c["foo"] = "first level"
>>> with c.update({"foo": "second level"}):
... c["foo"]
...
'second level'
>>> c["foo"]
'first level'
在 某些自訂範本標籤 中,將 Context
用作堆疊非常方便。
- Context.flatten()¶
透過使用 flatten()
方法,您可以將整個 Context
堆疊取得為一個包含內建變數的字典。
>>> c = Context()
>>> c["foo"] = "first level"
>>> c.update({"bar": "second level"})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
內部也會使用 flatten()
方法來使 Context
物件具有可比較性。
>>> c1 = Context()
>>> c1["foo"] = "first level"
>>> c1["bar"] = "second level"
>>> c2 = Context()
>>> c2.update({"bar": "second level", "foo": "first level"})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
在單元測試中,flatten()
的結果可以用來比較 Context
與 dict
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1["update"] = "value"
self.assertEqual(
c1.flatten(),
{
"True": True,
"None": None,
"False": False,
"update": "value",
},
)
使用 RequestContext
¶
- class RequestContext(request, dict_=None, processors=None, use_l10n=None, use_tz=None, autoescape=True)[原始碼]¶
Django 提供了一個特殊的 Context
類別,django.template.RequestContext
,其行為與一般的 django.template.Context
略有不同。第一個不同之處在於它將 HttpRequest
作為其第一個參數。例如:
c = RequestContext(
request,
{
"foo": "bar",
},
)
第二個不同之處在於,它會根據引擎的 context_processors
設定選項自動填充 context 一些變數。
context_processors
選項是一個可呼叫物件的列表(稱為 **context processors**),這些物件會將請求物件作為其參數,並傳回一個字典,其中的項目會合併到 context 中。在預設產生的設定檔中,預設的 template engine 包含以下 context processors:
[
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
除了這些之外,RequestContext
總是會啟用 'django.template.context_processors.csrf'
。這是一個與安全性相關的 context processor,admin 和其他 contrib 應用程式需要用到它,並且為了避免意外的錯誤設定,它被刻意地硬編碼在其中,無法在 context_processors
選項中關閉。
每個 processor 都會依序套用。這表示如果一個 processor 將變數新增到 context 中,而第二個 processor 新增了具有相同名稱的變數,則第二個 processor 會覆寫第一個。預設的 processors 解釋如下。
何時套用 context processors
Context processors 是在 context 資料之上套用的。這表示 context processor 可能會覆寫您提供給 Context
或 RequestContext
的變數,因此請注意避免與 context processors 提供的變數名稱重疊。
如果您希望 context 資料優先於 context processors,請使用以下模式:
from django.template import RequestContext
request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})
Django 這樣做的目的是允許 context 資料在諸如 render()
和 TemplateResponse
之類的 API 中覆寫 context processors。
此外,您可以使用可選的第三個位置參數 processors
,為 RequestContext
提供額外的 processor 列表。在這個範例中,RequestContext
實例會取得一個 ip_address
變數:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ip_address_processor(request):
return {"ip_address": request.META["REMOTE_ADDR"]}
def client_ip_view(request):
template = Template("{{ title }}: {{ ip_address }}")
context = RequestContext(
request,
{
"title": "Your IP Address",
},
[ip_address_processor],
)
return HttpResponse(template.render(context))
內建的 template context processors¶
以下是每個內建 processors 的功能:
django.contrib.auth.context_processors.auth
¶
如果啟用此 processor,則每個 RequestContext
將包含以下變數:
user
– 代表目前登入使用者的auth.User
實例(如果客戶端未登入,則為AnonymousUser
實例)。perms
–django.contrib.auth.context_processors.PermWrapper
的實例,代表目前登入使用者擁有的權限。
django.template.context_processors.debug
¶
如果啟用此 processor,則每個 RequestContext
將包含以下兩個變數 - 但前提是您的 DEBUG
設定設為 True
,並且請求的 IP 位址(request.META['REMOTE_ADDR']
)在 INTERNAL_IPS
設定中。
debug
–True
。您可以在 template 中使用它來測試是否處於DEBUG
模式。sql_queries
–{'sql': ..., 'time': ...}
字典的列表,表示到目前為止在請求期間發生的每個 SQL 查詢及其所花費的時間。該列表按資料庫別名排序,然後按查詢排序。它會在存取時延遲產生。
django.template.context_processors.i18n
¶
如果啟用此 processor,則每個 RequestContext
將包含以下變數:
LANGUAGES
–LANGUAGES
設定的值。LANGUAGE_BIDI
– 如果目前的語言是從右到左的語言(例如:希伯來語、阿拉伯語),則為True
。如果它是從左到右的語言(例如:英語、法語、德語),則為False
。LANGUAGE_CODE
– 如果存在request.LANGUAGE_CODE
。否則,為LANGUAGE_CODE
設定的值。
請參閱 i18n template tags,以取得產生相同值的 template tags。
django.template.context_processors.media
¶
如果啟用此 processor,則每個 RequestContext
將包含一個變數 MEDIA_URL
,提供 MEDIA_URL
設定的值。
django.template.context_processors.static
¶
如果啟用此處理器,每個 RequestContext
都會包含一個變數 STATIC_URL
,提供 STATIC_URL
設定的值。
django.template.context_processors.csrf
¶
此處理器會新增一個 token,該 token 是 csrf_token
模板標籤為了防止 跨網站請求偽造 所需的。
django.template.context_processors.request
¶
如果啟用此處理器,每個 RequestContext
都會包含一個變數 request
,它是目前的 HttpRequest
。
django.template.context_processors.tz
¶
如果啟用此處理器,每個 RequestContext
都會包含一個變數 TIME_ZONE
,提供目前啟用的時區名稱。
django.contrib.messages.context_processors.messages
¶
如果啟用此處理器,每個 RequestContext
都會包含這兩個變數
撰寫您自己的內容處理器¶
內容處理器有一個簡單的介面:它是一個 Python 函式,接受一個引數,即 HttpRequest
物件,並回傳一個字典,該字典會被新增到模板內容中。
例如,要將 DEFAULT_FROM_EMAIL
設定新增到每個內容中
from django.conf import settings
def from_email(request):
return {
"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
}
自訂內容處理器可以位於程式碼庫中的任何位置。Django 在意的是,您的自訂內容處理器是否已在 TEMPLATES
設定中的 'context_processors'
選項中指向,或者如果您直接使用 Engine
,則是在 context_processors
引數中指向。
載入模板¶
一般來說,您會將模板儲存在檔案系統上的檔案中,而不是自行使用低階的 Template
API。將模板儲存在指定為**模板目錄**的目錄中。
Django 會在多個位置搜尋模板目錄,這取決於您的模板載入設定(請參閱下方的「載入器類型」),但指定模板目錄最基本的方式是使用 DIRS
選項。
DIRS
選項¶
透過在設定檔中的 TEMPLATES
設定中使用 DIRS
選項,或在 Engine
中使用 dirs
引數,告訴 Django 您的模板目錄在哪裡。這應設定為一個字串清單,其中包含模板目錄的完整路徑。
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
"/home/html/templates/lawrence.com",
"/home/html/templates/default",
],
},
]
您的模板可以放在您想要的任何位置,只要目錄和模板可由網頁伺服器讀取即可。它們可以有任何您想要的擴充名稱,例如 .html
或 .txt
,或者它們可以完全沒有擴充名稱。
請注意,即使在 Windows 上,這些路徑也應使用 Unix 風格的正斜線。
載入器類型¶
預設情況下,Django 使用基於檔案系統的模板載入器,但 Django 也隨附了一些其他模板載入器,這些載入器知道如何從其他來源載入模板。
其中一些其他載入器預設為停用,但您可以透過將 'loaders'
選項新增至 TEMPLATES
設定中的 DjangoTemplates
後端,或將 loaders
引數傳遞給 Engine
來啟用它們。loaders
應該是一個字串或元組的清單,其中每個代表一個模板載入器類別。以下是 Django 隨附的模板載入器
django.template.loaders.filesystem.Loader
- class filesystem.Loader¶
根據
DIRS
從檔案系統載入模板。此載入器預設為啟用。但是,除非您將
DIRS
設定為非空的清單,否則它將找不到任何模板。TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], } ]
您也可以覆寫
'DIRS'
,並為特定的檔案系統載入器指定特定的目錄TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "OPTIONS": { "loaders": [ ( "django.template.loaders.filesystem.Loader", [BASE_DIR / "templates"], ), ], }, } ]
django.template.loaders.app_directories.Loader
- class app_directories.Loader¶
從檔案系統上的 Django 應用程式載入模板。對於
INSTALLED_APPS
中的每個應用程式,載入器都會尋找templates
子目錄。如果目錄存在,Django 會在那裡尋找模板。這表示您可以將模板與您的個別應用程式一起儲存。這也有助於發佈具有預設模板的 Django 應用程式。
例如,對於此設定
INSTALLED_APPS = ["myproject.polls", "myproject.music"]
...然後
get_template('foo.html')
將會按照以下順序在這些目錄中尋找foo.html
/path/to/myproject/polls/templates/
/path/to/myproject/music/templates/
... 並會使用它首先找到的那個。
INSTALLED_APPS
的順序非常重要!例如,如果您想要自訂 Django 管理介面,您可能會選擇使用您自己的myproject.polls
中的admin/base_site.html
覆寫來自django.contrib.admin
的標準admin/base_site.html
模板。然後,您必須確保您的myproject.polls
在INSTALLED_APPS
中先於django.contrib.admin
,否則django.contrib.admin
的會先載入,而您的則會被忽略。請注意,載入器在第一次執行時會執行最佳化:它會快取一份
INSTALLED_APPS
程式套件中哪些具有templates
子目錄的清單。您可以將
APP_DIRS
設定為True
來啟用此載入器TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "APP_DIRS": True, } ]
django.template.loaders.cached.Loader
- class cached.Loader¶
雖然 Django 模板系統速度相當快,但如果它需要在每次呈現時讀取和編譯您的模板,那麼由此產生的額外負荷可能會加重。
您可以使用它應該包裝的其他載入器清單來配置快取的模板載入器。當第一次遇到未知模板時,會使用包裝的載入器來尋找它們。然後,快取的載入器會將已編譯的
Template
儲存在記憶體中。對於後續載入相同模板的要求,會傳回快取的Template
執行個體。如果未指定
OPTIONS['loaders']
,則會自動啟用此載入器。您可以使用類似以下的設定,透過一些自訂的樣板載入器手動指定樣板快取:
TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "OPTIONS": { "loaders": [ ( "django.template.loaders.cached.Loader", [ "django.template.loaders.filesystem.Loader", "django.template.loaders.app_directories.Loader", "path.to.custom.Loader", ], ), ], }, } ]
注意
所有內建的 Django 樣板標籤都可安全地與快取載入器一起使用,但如果您正在使用來自第三方套件的自訂樣板標籤,或者您自己編寫的標籤,則應確保每個標籤的
Node
實作是執行緒安全的。有關更多資訊,請參閱樣板標籤執行緒安全考量。
django.template.loaders.locmem.Loader
- class locmem.Loader¶
從 Python 字典載入樣板。這對於測試很有用。
此載入器會將樣板字典作為其第一個引數
TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "OPTIONS": { "loaders": [ ( "django.template.loaders.locmem.Loader", { "index.html": "content here", }, ), ], }, } ]
此載入器預設為停用。
Django 會根據 'loaders'
選項依序使用樣板載入器。它會使用每個載入器,直到載入器找到符合的項目為止。
自訂載入器¶
可以使用自訂樣板載入器從其他來源載入樣板。自訂 Loader
類別應繼承自 django.template.loaders.base.Loader
,並定義 get_contents()
和 get_template_sources()
方法。
載入器方法¶
- class Loader[原始碼]¶
從給定的來源(例如檔案系統或資料庫)載入樣板。
- get_template_sources(template_name)[原始碼]¶
一個方法,它接受一個
template_name
並為每個可能的來源產生Origin
實例。例如,檔案系統載入器可能會收到
'index.html'
作為template_name
引數。此方法會為載入器所檢視的每個樣板目錄中出現的index.html
的完整路徑產生來源。此方法不需要驗證樣板是否存在於給定的路徑,但應確保路徑有效。例如,檔案系統載入器會確保路徑位於有效的樣板目錄下。
- get_contents(origin)¶
返回給定
Origin
實例的樣板內容。這是檔案系統載入器從檔案系統讀取內容,或資料庫載入器從資料庫讀取內容的地方。如果不存在相符的樣板,則應引發
TemplateDoesNotExist
錯誤。
- get_template(template_name, skip=None)[原始碼]¶
透過迴圈執行
get_template_sources()
的結果並呼叫get_contents()
,返回給定template_name
的Template
物件。這會返回第一個相符的樣板。如果找不到樣板,則會引發TemplateDoesNotExist
。選用的
skip
引數是在擴充樣板時要忽略的來源清單。這允許樣板擴充相同名稱的其他樣板。它也用於避免遞迴錯誤。一般來說,為自訂樣板載入器定義
get_template_sources()
和get_contents()
就足夠了。get_template()
通常不需要覆寫。
建構您自己的載入器
如需範例,請閱讀 Django 內建載入器的原始碼。
樣板來源¶
樣板具有一個 origin
,其中包含根據載入樣板來源而定的屬性。
- class Origin(name, template_name=None, loader=None)[原始碼]¶
- name¶
樣板載入器返回的樣板路徑。對於從檔案系統讀取的載入器,這是樣板的完整路徑。
如果樣板是直接實例化而不是透過樣板載入器實例化,則此字串值為
<unknown_source>
。
- template_name¶
傳遞到樣板載入器的樣板相對路徑。
如果樣板是直接實例化而不是透過樣板載入器實例化,則此值為
None
。
- loader¶
建構此
Origin
的樣板載入器實例。如果樣板是直接實例化而不是透過樣板載入器實例化,則此值為
None
。django.template.loaders.cached.Loader
要求其所有封裝的載入器都設定此屬性,通常是透過使用loader=self
實例化Origin
來完成。