一篇文章搞懂Jinja2 Template Engine 模版引擎
Flask和Django,以及其它很多Python框架,都預設使用Jinja2
來作為模版引擎。
在Python中,什麼是模版?就是在一個靜態HTML加入一些類似變數的標籤,然後引擎在渲染這個HTML時候會動態的把變數填入內容,生成一個最終的HTML。
什麼是模版引擎?其實就是一種能解析類似Python語言
的標記語言的直譯器。
比如我們在HTML模版中輸入一個<p> {{ post.title }} </p>
,顯然這不是真正的HTML語法。但是當Jinja2直譯器讀取到{{ ...}}
後知道里面是一個變數,那麼就把這個變數替換為真正的值,最後翻譯出來就變成了<p> 大標題 </p>
這樣的HTML內容。
Jinja2是一個模版語言,只是類似Python,比較符合Python語法,但不完全相同!
所有的模版引擎,實際上都差不多,不管是基於VBS語言的ASP模版,還是基於PHP語言的PHP模版,都不是與原本語言一摸一樣,而只是做到儘量一樣而已。
Jinja2語言基礎
注意:Jinja2
模版語言,是不區分縮排的,和純python不同。實際上所有模版語言都不區分縮緊。
常用標記:
-
註釋:
{# 這是註釋 #}
-
變數:
{{ post.title }}
,或字典元素{{your_dict['key']}}
,或列表{{your_list[0]}}
-
多行程式碼塊:
{% 開始 %} HTML標籤 {% 結束 %}
示例:
{% if user %} {{ user }} {% else %} hello! {% for index in indexs %} {{ index }} {% endfor %}
Jinja2 Filter 過濾器 (即函式)
一個filter過濾器的本質就是一個function函式。使用格式為:變數名 | 函式
。
它做到的就是,把變數傳給函式,然後再把函式返回值作為這個程式碼塊的值。
如:
<!-- 帶引數的 --> {{變數 | 函式名(*args)}} <!-- 不帶引數可以省略括號 --> {{變數 | 函式名}}
鏈式呼叫(管道式):
和命令列的pipline管道一樣,可以一次呼叫多個函式(過濾器),如:
{{ "hello world" | reverse | upper }}
文字塊呼叫(將中間的所有文字都作為變數內容傳入到過濾器中):
{% filter upper %} 一大堆文字 {% endfilter %}
Jinja2常用內建函式(過濾器)
字串操作:
safe:禁用轉義 <p>{{ '<em>hello</em>' | safe }}</p> capitalize:把變數值的首字母轉成大寫,其餘字母轉小寫 <p>{{ 'hello' | capitalize }}</p> lower:把值轉成小寫 <p>{{ 'HELLO' | lower }}</p> upper:把值轉成大寫 <p>{{ 'hello' | upper }}</p> title:把值中的每個單詞的首字母都轉成大寫 <p>{{ 'hello' | title }}</p> reverse:字串反轉 <p>{{ 'olleh' | reverse }}</p> format:格式化輸出 <p>{{ '%s is %d' | format('name',17) }}</p> striptags:渲染之前把值中所有的HTML標籤都刪掉 <p>{{ '<em>hello</em>' | striptags }}</p> truncate: 字串截斷 <p>{{ 'hello every one' | truncate(9)}}</p>
列表操作:
first:取第一個元素 <p>{{ [1,2,3,4,5,6] | first }}</p> last:取最後一個元素 <p>{{ [1,2,3,4,5,6] | last }}</p> length:獲取列表長度 <p>{{ [1,2,3,4,5,6] | length }}</p> sum:列表求和 <p>{{ [1,2,3,4,5,6] | sum }}</p> sort:列表排序 <p>{{ [6,2,3,1,5,4] | sort }}</p>
Jinja2 Macro 巨集 (自定義函式)
Jinja2是允許自定義函式的,這樣在模版中可以重複利用這個自定義函式。Jinja2稱之為Macro
巨集。
定義方法:
{% macro 函式名(引數) %} 具體的HTML內容 {% endmacro %} <!-- 使用 --> {{ 函式名(引數) }} <!-- 或作為過濾器 --> {{ 變數 | 函式名(引數) }}
關於Jinja2自定義函式的context
上下文和環境變數的問題:
Jinja2的自定義函式“巨集”,本身是沒法像filter過濾器函式一樣使用上下文和環境變數的。
不過可以加上@contextfilter
裝飾器達到同樣的效果。
匯入另一個檔案的自定義函式“巨集”:
假設在macro.html
檔案中我們定義了一個函式func()
。
那麼現在我們可以在另一個檔案reference.html
中像python匯入模組一樣匯入它:
{% import 'macro.html' as module %} {{ module.func() }}
Include 模版引用
Include是我們常用的操作,即定義一個框架模版(父模版),然後一個一個指定性的把子模版引入進來。
框架模版frame.html
如下:
{% include 'header.html' %} {% include 'body.html' %} {% include 'footer.html' %}
Extend 模版繼承
我們可以在一個父模版中定義一個block
程式碼塊,然後在另一個子模版中“繼承”這個父模版,並重寫這個block
程式碼塊。
不過一般模版中的父模版,都只是留出一個block
空位,裡面不寫東西,特意等子模版來實現。
假設現在有一個父模版parent.html
:
{% block HEADER %} 頁頭部分的HTML內容。 {% endblock HEADER %} {% block BODY %} 正文部分的HTML內容。 {% endblock BODY %} {% block FOOTER %} 頁尾部分的HTML內容。 {% endblock FOOTER %}
其中定義了三個block,頁頭、正文和頁尾。
然後我們就可以定義一個模版child.html
來繼承父模版,並且只重寫BODY部分:
{% extends 'parent.html' %} {% block BODY %} 由子頁面重寫改寫的的HTML內容,替換父頁面的BODY。。。 {% endblock BODY %}
擴充套件完成後,我們最終得到的結果是:
{% block HEADER %} 頁頭部分的HTML內容。 {% endblock HEADER %} {% block BODY %} 由子頁面重寫改寫的的HTML內容,替換父頁面的BODY。。。 {% endblock BODY %} {% block FOOTER %} 頁尾部分的HTML內容。 {% endblock FOOTER %}
Jinja2模版引用Flask路由中的內容
在Flask應用Jinja2模版時,在模版中可以直接呼叫Flask app中的一些公用變數和方法。
引用Flask的request
物件:
<p> {{ request.url }} </p> <p> {{ request.form.get('name') }} </p>
引用Flask的url_for(...)
方法:
<!-- 它會返回我們定義的路由`app.route('/index')`所對應的URL --> <p> {{ url_for('index') }} </p> <!-- 它會返回我們定義的路由`app.route('/post/{post_id}')`所對應的URL --> <p> {{ url_for('post', post_id='127') }} </p>
在模版中,我們可以引用get_flashed_messages()
方法,獲取Flask路由傳來的閃現資訊
:
{% for msg in get_flashed_messages() %} <p> {{ msg }} </p> {% endfor %}
這種閃現資訊是從Flask路由中傳來的,只要在路由中發一個flash('hello')
資訊,相當於彈了一個alert()
。然後我們可以在Jinja2的模版中用get_flashed_messages()
獲得flash過來的資訊列表。