Django4.0 模板-模板引擎的支持

2022-03-16 17:58 更新

配置

模板引擎是通過(guò) ?TEMPLATES ?進(jìn)行配置。這是一個(gè)配置列表,每個(gè)引擎都有一個(gè)。默認(rèn)值為空。?startproject ?命令生成的 ?settings.py? 定義了一個(gè)更有用的值:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            # ... some options here ...
        },
    },
]

?BACKEND ?是實(shí)現(xiàn) Django 模板后端 API 的模板引擎類(lèi)的點(diǎn)分隔 Python 路徑。內(nèi)置的后端有 ?django.template.backends.django.DjangoTemplates? 和 ?django.template.backends.jinja2.Jinja2?。
由于大多數(shù)引擎都是從文件中加載模板,因此每個(gè)引擎的頂層配置都包含兩個(gè)常見(jiàn)的配置:

  • ?DIRS ?定義了目錄列表,引擎應(yīng)在其中按搜索順序查找模板源文件。
  • ?APP_DIRS ?告訴引擎是否應(yīng)該在已安裝的應(yīng)用程序中尋找模板。每個(gè)后端都為應(yīng)用程序中存儲(chǔ)模板的子目錄定義了一個(gè)慣用名稱(chēng)。

雖然不常見(jiàn),但可以使用不同的選項(xiàng)配置同一后端的多個(gè)實(shí)例。 在這種情況下,你應(yīng)該為每個(gè)引擎定義一個(gè)唯一的 ?NAME?。
?OPTIONS ?包含特定于后端的配置。

用法

?django.template.loader? 模塊定義了兩個(gè)加載模板的函數(shù)。

get_template(template_name, using=None)

此函數(shù)使用給定名稱(chēng)加載模板并返回 ?Template ?對(duì)象。
返回值的確切類(lèi)型取決于加載模板的后端。 每個(gè)后端都有自己的 ?Template ?類(lèi)。
?get_template()? 依次嘗試每個(gè)模板引擎,直到成功為止。如果找不到模板,則會(huì)引發(fā) ?TemplateDoesNotExist ?錯(cuò)誤。如果找到模板但包含無(wú)效語(yǔ)法,則會(huì)引發(fā) ?TemplateSyntaxError ?錯(cuò)誤。
搜索和加載模板的方式取決于每個(gè)引擎的后端和配置。
如果你想把搜索限制在一個(gè)特定的模板引擎上,在 ?using ?參數(shù)中傳遞該引擎的 ?NAME?。

select_template(template_name_list, using=None)

?select_template() ?就像 ?get_template()?,不同的是,它接受一個(gè)模板名稱(chēng)的列表。它按順序嘗試每個(gè)名字,并返回第一個(gè)存在的模板。

如果加載模板失敗,則可能會(huì)引發(fā)在 ?django.template? 中定義的以下兩個(gè)異常:

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)

當(dāng)找不到模板時(shí)引發(fā)此異常。

  • ?backend?:產(chǎn)生異常的模板后端實(shí)例。
  • ?tried?:查找模板時(shí)嘗試過(guò)的來(lái)源列表。它的格式為包含 (origin, status) 的元組列表,其中 origin 是一個(gè) 類(lèi) origin 對(duì)象而 status 是一個(gè)說(shuō)明找不到模板原因的字符串。
  • ?chain?:嘗試加載模板時(shí)引發(fā)的一系列中間 TemplateDoesNotExist 異常列表。這由函數(shù)使用,例如:get_template(),這些函數(shù)嘗試從多個(gè)引擎加載給定的模板。

exception TemplateSyntaxError(msg)

當(dāng)找到模板但包含錯(cuò)誤時(shí),將引發(fā)此異常。

由 ?get_template()? 和 ?select_template()? 返回的 ?Template ?對(duì)象必須提供具有以下簽名的?render()?方法:

Template.render(context=None, request=None)

  • 使用給定的上下文渲染此模板。
  • 如果提供了 ?context ?,則必須是 ?dict?。如果未提供,則引擎將使用空上下文渲染模板。
  • 如果提供了 ?request?,它必須是 ?HttpRequest?。同時(shí)引擎必須使它和 CSRF 令牌在模板中可用。如何實(shí)現(xiàn)這一點(diǎn)由每個(gè)后端決定。

下面是一個(gè)搜索算法的例子。在這個(gè)例子中 ?TEMPLATES ?設(shè)置為:

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',
        ],
    },
]

如果你調(diào)用 ?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?引擎)

如果你調(diào)用 ?select_template(['story_253_detail.html', 'story_detail.html'])?,Django 將尋找以下內(nèi)容:

  • ?/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 ?引擎)

當(dāng) Django 發(fā)現(xiàn)一個(gè)模板存在時(shí),它就會(huì)停止尋找。

提示:你可以使用 ?select_template()? 靈活的加載模板。例如,如果你寫(xiě)了一個(gè)新聞故事,并希望一些故事有自定義模板,使用類(lèi)似 ?select_template(['story_%s_detail.html' % story.id, 'story_detail.html'])? 。這將允許你為單個(gè)故事使用自定義模板,為沒(méi)有自定義模板的故事使用備用模板。

最好是在每個(gè)包含模板的目錄內(nèi)的子目錄中組織模板。慣例是為每個(gè) Django 應(yīng)用程序創(chuàng)建一個(gè)子目錄,根據(jù)需要在這些子目錄中包含子目錄。
要加載子目錄中的模板,請(qǐng)使用斜杠,如下所示:

get_template('news/story_detail.html')

使用與上述相同的 ?TEMPLATES ?選項(xiàng),這將嘗試加載以下模板:

  • ?/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 ?引擎)

此外,為了減少加載和渲染模板的重復(fù)性,Django 提供了一個(gè)自動(dòng)處理的快捷函數(shù)。

render_to_string(template_name, context=None, request=None, using=None)

?render_to_string()? 加載一個(gè)模板 ?get_template() ?,并立即調(diào)用它的? render() ?方法。它需要下面的參數(shù)。

  • ?template_name?:加載和呈現(xiàn)模板的名稱(chēng)。如果是模板名稱(chēng)列表,Django 使用 select_template() ,而不是 get_template() 找到模板。
  • ?context?:?dict ?用作模板的渲染上下文。
  • ?request?:可選項(xiàng) ?HttpRequest ?在模板的渲染過(guò)程中可用。
  • ?using?:可選的模板引擎 ?NAME?。對(duì)模板的搜索將限于該引擎。

使用實(shí)例:

from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', {'foo': 'bar'})

還可以用 ?render()? 快捷函數(shù),它調(diào)用 ?render_to_string()? ,并將結(jié)果提供給 ?HttpResponse ?,適合從視圖返回。
最后,您可以直接使用配置好的引擎:

engines

模板引擎可在 ?django.template.engines? 中使用:

from django.template import engines

django_engine = engines['django']
template = django_engine.from_string("Hello {{ name }}!")

在這個(gè)例子中,查找關(guān)鍵字“django”是引擎的 ?NAME?。

內(nèi)置后端

class DjangoTemplates

設(shè)置 ?BACKEND ?為 ?django.template.backends.django.DjangoTemplates?,以配置 Django 模板引擎。
當(dāng) ?APP_DIRS ?為 ?True ?時(shí),?DjangoTemplates ?引擎會(huì)在已安裝應(yīng)用程序的 ?templates ?子目錄中尋找模板。這個(gè)通用名稱(chēng)是為了向后兼容而保留的。

?DjangoTemplates引擎接受以下 ?OPTIONS?:

?autoescape?:一個(gè)布爾值,控制是否啟用 HTML 自動(dòng)轉(zhuǎn)義。默認(rèn)為 ?True?。只有當(dāng)你渲染非 HTML 模板時(shí),才將其設(shè)置為 ?False?!

?context_processors?:當(dāng)模板被請(qǐng)求渲染時(shí),用于填充上下文的可調(diào)用項(xiàng)的點(diǎn)分隔 Python 路徑列表。這些可調(diào)用的對(duì)象以一個(gè)請(qǐng)求對(duì)象作為參數(shù),并返回一個(gè) ?dict ?的項(xiàng)目,這些項(xiàng)目將被合并到上下文中。默認(rèn)為空列表。

?debug?:開(kāi)啟/關(guān)閉模板調(diào)試模式的布爾值。如果是 ?True?,錯(cuò)誤頁(yè)面將顯示模板渲染過(guò)程中出現(xiàn)的任何異常的詳細(xì)報(bào)告。該報(bào)告包含模板的相關(guān)片段,并突出顯示相應(yīng)的行。
默認(rèn)為 ?DEBUG ?配置的值。

?loaders?:模板加載器類(lèi)的點(diǎn)分隔 Python 路徑列表。每個(gè) ?Loader ?類(lèi)都知道如何從特定源導(dǎo)入模板??梢赃x擇使用元組來(lái)代替字符串。元組中的第一項(xiàng)應(yīng)該是 ?Loader ?類(lèi)名,隨后的項(xiàng)在初始化期間傳遞給 ?Loader?。默認(rèn)值取決于 ?DIRS ?和 ?APP_DIRS ?的值。

?string_if_invalid?:模板系統(tǒng)對(duì)無(wú)效變量(如拼寫(xiě)錯(cuò)誤)應(yīng)將此字符串輸出。默認(rèn)為空字符串。

?file_charset?:用于讀取磁盤(pán)上模板文件的字符集。默認(rèn)為 utf-8。

?libraries?:模板標(biāo)簽?zāi)K的標(biāo)簽字典和點(diǎn)分隔 Python 路徑,用于向模板引擎注冊(cè)。 這可用于添加新庫(kù)或?yàn)楝F(xiàn)有庫(kù)提供替代標(biāo)簽。例如:

OPTIONS={
    'libraries': {
        'myapp_tags': 'path.to.myapp.tags',
        'admin.urls': 'django.contrib.admin.templatetags.admin_urls',
    },
}

可以通過(guò)將相應(yīng)的字典鍵傳遞到 ?{% load %}? 標(biāo)簽來(lái)加載庫(kù)。

?builtins?:要添加的 內(nèi)置模板標(biāo)簽和過(guò)濾器 的點(diǎn)分隔 Python 路徑列表。例如:

OPTIONS={
    'builtins': ['myapp.builtins'],
}

可以使用內(nèi)置庫(kù)中的標(biāo)簽和過(guò)濾器,而不需要先調(diào)用 ?{% load %}? 標(biāo)簽。

class Jinja2

需要安裝 Jinja2:

...\> py -m pip install Jinja2

設(shè)置 ?BACKEND ?為 django.template.backends.jinja2.Jinja2?以配置一個(gè) Jinja2 引擎。
當(dāng) ?APP_DIRS ?為 ?True ?時(shí),Jinja2 引擎會(huì)在安裝的應(yīng)用程序的 jinja2 子目錄中查找模板。
?OPTIONS ?中最重要的條目是 ?environment?。它是一個(gè)點(diǎn)分隔 Python 路徑,指向一個(gè)返回 Jinja2 環(huán)境的可調(diào)用對(duì)象。默認(rèn)為 ?jinja2.Environment?。Django 調(diào)用該可調(diào)用對(duì)象并傳遞其他選項(xiàng)作為關(guān)鍵字參數(shù)。此外,Django 為一些選項(xiàng)添加了不同于 Jinja2 的默認(rèn)值。

  • ?autoescape?:?True?
  • ?loader?:為 ?DIRS ?和 ?APP_DIRS ?配置的加載器
  • ?auto_reload?:?settings.DEBUG?
  • ?undefined?:?DebugUndefined if settings.DEBUG else Undefined?

Jinja2 引擎也接受以下 ?OPTIONS?:

?context_processors?:當(dāng)模板被請(qǐng)求渲染時(shí),用于填充上下文的可調(diào)用項(xiàng)的點(diǎn)分隔 Python 路徑列表。這些可調(diào)用的對(duì)象以一個(gè)請(qǐng)求對(duì)象作為參數(shù),并返回一個(gè) ?dict ?的項(xiàng)目,這些項(xiàng)目將被合并到上下文中。默認(rèn)為空列表

不建議將上下文處理器與 Jinja2 模板一起使用。

上下文處理器在 Django 模板中很有用,因?yàn)?Django 模板不支持調(diào)用帶參數(shù)的函數(shù)。由于 Jinja2 沒(méi)有此限制,因此建議將你要用作上下文處理器的函數(shù)放在模板的全局變量 ?jinja2.Environment? 中使用,如下所述。然后你可以在模板中調(diào)用該函數(shù)。

{{ function(request) }}

有些 Django 模板的上下文處理器會(huì)返回一個(gè)固定的值。對(duì)于 Jinja2 模板,不需要這一層間接操作,因?yàn)槟梢灾苯釉??jinja2.Environment? 中添加常量。
最初為 Jinja2 增加上下文處理器的用例涉及:

  • 根據(jù)請(qǐng)求進(jìn)行昂貴的計(jì)算。
  • 在每個(gè)模板中都需要結(jié)果。
  • 在每個(gè)模板中多次使用結(jié)果。

除非滿(mǎn)足所有這些條件,否則將函數(shù)傳遞給模板更符合 Jinja2 的設(shè)計(jì)。

默認(rèn)配置被有意地保持為最低。如果一個(gè)模板被請(qǐng)求渲染(例如,當(dāng)使用 ?render()?),Jinja2 后端會(huì)在上下文中添加 ?request?,?csrf_input ?和 ?csrf_token?。除此之外,此后端不會(huì)創(chuàng)建 Django 風(fēng)格的環(huán)境。 它不知道 Django 過(guò)濾器和標(biāo)簽。 為了使用 Django 特有的 API,你必須將它們配置到環(huán)境中。

例如,您可以使用以下內(nèi)容創(chuàng)建 ?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? 選項(xiàng)設(shè)置為 ?myproject.jinja2.environment?
這樣你就可以在 Jinja2 模板中使用以下構(gòu)造:

<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">

<a href="{{ url('admin:index') }}">Administration</a>

Django 模板語(yǔ)言和 Jinja2 中都存在標(biāo)簽和過(guò)濾器的概念,但使用方式不同。由于 Jinja2 支持在模板中向可調(diào)用對(duì)象傳遞參數(shù),所以很多在 Django 模板中需要模板標(biāo)簽或過(guò)濾器的功能都可以通過(guò)在 Jinja2 模板中調(diào)用函數(shù)來(lái)實(shí)現(xiàn),如上例所示。Jinja2 的全局命名空間消除了對(duì)模板上下文處理器的需求。Django 模板語(yǔ)言并沒(méi)有與 Jinja2 測(cè)試相對(duì)應(yīng)的功能。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)