1. 程式人生 > Django入門教學 >11 模板系統基礎

11 模板系統基礎

Django 中的模板系統是 Django 框架的重要組成部分。無論哪一個 Web 框架都需要提供動態生成 HTML 頁面的方式,最常用的做法是使用模板。模板包含一些公共的 HTML 部分以及一些特殊的語法,該語法用於描述如何將資料動態插入 HTML 網頁中。

Django 框架後端預設支援自生內建的一套模板系統 DTL (Django Template Language) 和著名的 Jinja2 模板系統。除此之外,還可以從第三方模組中選擇其他模板系統。往往內建的模板系統以及 Jinja2 已經足夠應對大多數場景了。

1. 什麼是模板

模板在生活中也是非常常見的,比如我們上學時向老師請假,會有請假條的模板,只需在請假條模板中填寫請假人以及請假原因就可以。HTML 的模板也是如此,只不過我們會有特殊的語法來完成一個模板,接下來會有對應的模板引擎來幫我們將傳入的資料和模板中變數進行一一對應並最終形成一個完整的 HTML 檔案。例如下面的一個最簡單的模板檔案:

<html>
<head></head>
<style type="text/css">
</style>
<body>
<h1>{{ title }}</h1>
</body>
</html>

這個簡單的模板中,我們只有一個模板變數 title,用 {{}} 括起來。模板引擎會對這些變數進行資料替換,比如傳入資料 {'title':'標題1'},那麼模板引擎就會將 {{ title }} 直接替換成 標題1 字串。不同的模板引擎支援不同的語法格式。在 Django 中應用最為廣泛的模板引擎當屬 Jinja2 了,當然它也是 Flask 框架預設使用的模板系統。

2. Python中的模板庫

Python 中比較出名的模板庫有 2 個,分別是 Mako 和 Jinja2。下面分別來說一說這兩個模板庫的用法和一些特點。

Mako 是一個高效能的 Python 模板庫,它的語法和 API 借鑑了很多其他的模板庫,如 Django、Jinja2 等等。它聲稱有比 Jinja2 更快的解析速度以及更多的語法支援。我們來簡單過一遍 Mako 中模板語法並用一個案例進行測試:

  • 變數寫法:${variable},在花括號中還可以執行一些 Python 的語法,如:${name.upper()} 會將 name 的值轉換成大寫;

  • 註釋:單行註釋用 ##,多行註釋用 <%doc></%doc>

    ## 兩個#號表示單行註釋
    <%doc>
    多行註釋
    </%doc>
    
  • if 條件語句:控制結構的語法都是以 % name 開頭,以 % end 結尾;

    % if i == 1:
        ${i}
    % endif
    
  • for 迴圈:for 迴圈的語法是以 % for 開頭,以 % endfor 結尾;

    % for a in [1, 2, 3, 4, 5]:
        % if a[0] == 1:
        its one
        % elif a[0] == 2:
        two
        % else:
        others
        % endif
    % endfor
    
  • Python 程式碼塊:Mako 中嵌入 python 程式碼塊時,使用標籤 <%%>

    <%
    x=1000
    y='imooc'
    z=y.upper()
    %>
    ${x}
    ${y}
    ${z}
    

接下來,我們用編寫簡單的 Python 程式碼測試下前面用的這些模板語法,基於 Mako 模板引擎來將如下的模板檔案渲染成完整的內容:

## coding=utf-8

<html>
<head></head>
<style type="text/css">
</style>
<body>
<h1>${title}</h1>
## 列印告警資訊    
% if has_warn == 'warning':
      ${warn_msg}  
% endif    

## 列印動物列表 
<ul>    
% for animal in animals:
    <li>${animal}</li>
% endfor 
</ul>
    
## 測試 python 程式碼塊
<%
x='imooc'
y=x.upper()
%>
<div>小寫:${x}</div>
<div>大寫:${y}</div>    
</body>
</html>

測試的 Python 程式碼如下:

# 先要安裝 mako 模組: pip install mako
# 程式碼檔名為 test_mako.py
from mako.template import Template
from mako.lookup import TemplateLookup
html_path = '/root/spyinx'

lookup = TemplateLookup(
    directories=[html_path],
    output_encoding='utf-8',
    input_encoding='utf-8',
    default_filters=['decode.utf8'],
    encoding_errors='replace'
)
# 檔案的全路徑為/root/spyinx/index.html
tp = lookup.get_template("/index.html")
values = {
    'title': '測試模板轉換',
    'has_warn': 'warning',
    'warn_msg': '這是一條告警資訊',
    'animals': ['獅子', '老虎', '蛇']
}
print(str(tp.render(**values), encoding="utf-8"))

執行的結果如下:

(env-3.8.1) [root@server spyinx]# ls
index.html  test_mako.py
(env-3.8.1) [root@server spyinx]# python test_mako.py 

<html>
<head></head>
<style type="text/css">
</style>
<body>
<h1>測試模板轉換</h1>
      這是一條告警資訊  

<ul>    
    <li>獅子</li>
    <li>老虎</li>
    <li>蛇</li>
</ul>
    

<div>小寫:imooc</div>
<div>大寫:IMOOC</div>    
</body>
</html>

可以看到這裡的模板文字已經被 Mako 引擎進行了更新,替換了其中的模板變數,去掉了註釋部分,形成了最終的文字。

接下來,我們也簡單介紹下 Jinja2 模板庫,它的用法和 Mako 幾乎是類似的,只不過支援的模板語法略有不同。我們會在後面詳細介紹 Jinja2,這裡簡單介紹一些常用的語法並使用 Python 程式碼進行測試。

  • 變數寫法:{{ variable }}

  • 註釋:註釋的語句是 {# 註釋部分 #}

  • 條件語句:條件語句大多使用 if 語句,它也具有單分支,多分支等多種結構。使用時需要以 endif 關鍵字結尾,而且 if 、elif、else 和 endif 都需要用 {%%} 包裹;

    {% if spyinx.age < 18 %}
    spyinx is a minor
    {% elif spyinx.age > 50 %}
    spyinx is an old man
    {% else %}
    spyinx is an adult
    {% endif %}
    
  • 迴圈語句:迴圈語句大部分使用 for 語句,它的寫法如下,和 mako 十分類似,使用 {%%} 包裹迴圈語句,還需要 {% endfor %} 結尾。

    {% for animal in animals %}
    {{ animal }}
    {% endfor %}
    

除了這些之外,還有過濾器、巨集、模板的繼承等等各種強大的功能,全方位滿足各種場景。這些會留到後面詳細介紹,下面來完成一個實驗,使用 Jinja2 模板庫完成對一個 Jinja2 模板檔案的轉換:

  • 準備好一個模板檔案 index.html.j2,內容如下:

    <html>
    <head></head>
    <style type="text/css">
    </style>
    <body>
    <h1>{{ title }}</h1>
    {# 列印告警資訊 #}
    {%- if has_warn == 'warning' -%}
    {{ warn_msg }}
    {%- endif -%}
    
    {# 列印動物列#}
    <ul>
    {%- for animal in animals %}
        <li>{{ animal }}</li>
    {%- endfor %}
    </ul>
    
    <div>首字母大寫:{{ 'imooc' | capitalize  }}</div>
    <div>大寫:{{ 'imooc' | upper }}</div>
    </body>
    </html>
    

    注意:這裡使用 {%- 的寫法是為了去掉類似 {% if|for|endif|endfor ... %} 這樣的語句產生的空格。

  • 準備好測試的 python 程式碼,如下:

    """
    測試 jinja2 模組
    """
    from jinja2 import Environment, FileSystemLoader
    
    def render_template(path, file_name, vars):
        env = Environment(loader=FileSystemLoader('./'))   # 載入模板
        template = env.get_template(file_name)
        content = template.render(vars)
        print(content)
        
    
    if __name__ == '__main__':
        values = {
           'title': '測試模板轉換',
           'has_warn': 'warning',
           'warn_msg': '這是一條告警資訊',
           'animals': ['獅子', '老虎', '蛇']
        }
        render_template('./', 'index.html.j2', values)
    
  • 執行該 python 程式碼,我們可以得到和前面 Mako 模板庫一樣的結果:

    (env-3.8.1) [root@server spyinx]# python test_jinja2.py 
    <html>
    <head></head>
    <style type="text/css">
    </style>
    <body>
    <h1>測試模板轉換</h1>
    這是一條告警資訊
    <ul>
        <li>獅子</li>
        <li>老虎</li>
        <li>蛇</li>
    </ul>
        
    <div>首字母大寫:Imooc</div>
    <div>大寫:IMOOC</div>    
    </body>
    </html>
    

至此,我們對 Python 中的模板庫有了初步的認識,接下來就來看看 Django 中的模板系統,包括如何配置和使用。

3. 小結

本小節中,我們講解了 Django 中模板系統的相關基礎知識,然後簡單學習了 Python 中的 2 個流行的模板庫 MakoJinja2 並進行了程式碼測試。接下來便是正式開始深入 Django 中的模板系統,包括模板語法、過濾器以及自定義過濾器等。