邊做邊學Python Flask Web開發(5)-- 使用Jinjia2模板(中)
上一篇介紹了Jinjia2模板系統的基本用法,本篇將深入對Jinjia2進行探討,對網頁設計中經常會用到的一些高階特性進行介紹。
模板複用
複用是網頁設計非常常用的特性,比如我們的頁面頭部的網站名稱和頁尾的版權標識通常都是一樣的,我們的選單有時候在每個頁面也都是一樣的。作為一名程式設計師,重複做同樣的事情是完全不可接受的。在Jinjia2中,通常可以使用繼承、包含和巨集三種特性來完成模板的利用。
繼承
這和類的繼承沒有什麼分別,因此也就有了父模板和子模板的概念。例如,我們可以把包含HTML框架、頁頭、頁尾的模板頁做為父模板,其它的子模板只需要繼承它,就自動擁有了頭部和尾部。
下面是一個父模板的例子:
<html>
<head>
{% block head %}
<title>{% block title %}Base Title{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
<h1>This Header is inherited from base.html</h1>
{% block body %} {% endblock %}
<hr/>
This footer is inherited from base.html
</body >
</html>
現在我們在templates目錄新建一個檔案,寫下一行程式碼,儲存為child.html
{% extends "base.html" %}
在建立了Flask app的原始碼中加上一個路由/child,完整的程式碼如下:
import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/child')
def child1():
return render_template("child.html")
if __name__ == '__main__':
app.run(debug=True)
執行這個程式我們看到如下的結果:
注意紅色標記的部分,這個頁面的title仍然是Base Title,原因是我們在子模板中並沒有對{% block title %}進行改寫。將child.html擴充:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% block body %}<h2> This is body of child1 </h2> {% endblock %}
再看看頁面的標題已被替換,body部分也被充實了內容。
模板繼承中,可以使用一個特殊的super函式,將父模板內容塊中定義的內容附加到子模板中,這有點像Python類的super函式。
{% block title%}
Child1 -
{{ super() }}
{% endblock %}
大家可以動手試一下這樣寫的話頁面的標題會變成什麼樣子。
包含
可以使用include將一個獨立的模板檔案包含進來,這一點和PHP非常相似。我們繼續修改child.html:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}<h2> This is body of child1 </h2> {% endblock %}
同時,新建一個名稱是menu.html的模板檔案,放置在同一目錄下,內容如下:
<hr/>
<ul>
<li>Menu Item 1</li>
<li>Menu Item 2</li>
<li>Menu Item 3</li>
<hr/>
現在的頁面已經包含了一個選單項。
巨集
最後我們介紹一下巨集。巨集的概念和大家瞭解的Office中的巨集很類似,它通常用來做一些需要多次處理的簡單工作。Jinjia2中定義和使用巨集有點像定義和使用函式,下面繼續我們的child.html,在裡面新增上巨集的定義和呼叫程式碼。
<!--這裡先定義巨集-->
{% macro render_comment(comment) %}
<li>MACRO:{{ comment }}</li>
{% endmacro %}
<!--定義結束-->
<!--呼叫巨集-->
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
<!--呼叫結束-->
我們還可以把巨集程式碼放置在一個單獨的檔案中,下面我們新建一個檔案macros.html,內容如下:
{% macro render_comment_from_file(comment) %}
<li>來自檔案:{{ comment }}</li>
{% endmacro %}
從檔案中載入巨集程式碼用到了一個新的命令import,繼續修改child.html,增加以下內容
<h4>這是由從檔案匯入的巨集生成的</h4>
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
{{ macros.render_comment_from_file(comment) }}
{% endfor %}
</ul>
至此,完整的child.html檔案如下:
{% extends "base.html" %}
{% block title %} Child1 {% endblock %}
{% include 'menu.html' %}
{% block body %}
<h2> This is body of child1 </h2>
<!--這裡先定義巨集-->
{% macro render_comment(comment) %}
<li>MACRO:{{ comment }}</li>
{% endmacro %}
<!--定義結束-->
<!--呼叫巨集-->
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
<!--呼叫結束-->
<h4>這是由從檔案匯入的巨集生成的</h4>
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
{{ macros.render_comment_from_file(comment) }}
{% endfor %}
</ul>
{% endblock %}
格式化
前幾章中我們瞭解到,Jinjia2的工作模式是向模板傳送資料再渲染成HTML頁面。不過在很多情況下,傳送到頁面的資料並不是我們期望的格式,這時候就要用到它的格式化功能。
Jinjia2中的格式化操作最常見的是使用過濾器進行的。
字串
我們用一個例子對字串的格式化操作進行說明,將下面的程式碼儲存為strings.html
<h1>Hello {{user}}</h1>
<hr />
<p>轉為首字母大寫: Hello, {{ user|capitalize }}</p>
<p>轉為大寫: Hello, {{ user|upper }}</p>
<p>轉為小寫: Hello, {{ user|lower }}</p>
<p>轉為標題樣式(每個主題詞首字母大寫): Hello, {{ user|title }}</p>
<p>去掉首尾空格(頁面上無效果): Hello, {{ user|trim }}</p>
<p>預設的HTML過濾操作: {{ myhtmlstr }}</p>
<p>新增safe過濾器(有安全隱患,如果不能確認字串是安全的請不要使用!): {{ myhtmlstr|safe }}</p>
<p>過濾掉HTML標記: {{ myhtmlstr|striptags }}</p>
<hr />
在建立了Flask app的原始碼中加上一個路由/strings,完整的程式碼如下:
import json,pprint,sys
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/strings')
def strings():
return render_template("strings.html",user="ivan wang",
myhtmlstr="<strong>this is <i>emphasized</i></strong>")
if __name__ == '__main__':
app.run(debug=True)
該頁面在瀏覽器中顯示如下
數字
仍然使用一個例子來演示數字的格式化方法,將下面的程式碼儲存為numerics.html:
<h2>和數字相關的過濾器</h2>
<p>四捨五入:{{n1|round}}</p>
<p>保留3位小數並四捨五入:{{n1|round(3)}}</p>
<p>保留1位小數下取整:{{n1|round(1,'floor')}}</p>
<p>保留1位小數上取整:{{n1|round(1,'ceil')}}</p>
<p>取整:{{n1|int}}</p>
<p>使用格式化字串:{{"%.2f" % n1}}</p>
<p>使用string.format函式進行千分位顯示:{{"{:,}".format(n2)}}</p>
<p>使用string.format函式對多個數字進行格式化:{{"Number1:{0:.2%}, Number2:{1:,}".format(n1,n2)}}</p>
在python程式碼中新增一個numerics路由:
@app.route('/numerics')
def numerics():
return render_template("numerics.html",n1=3.14159,n2=29838721)
頁面顯示如下:
自定義
如果所有內建的過濾器都不能滿足要求,Jinja2還允許你建立自定義的過濾器。
新增一個userdefined路由,程式碼如下:
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
@app.route('/userdefined')
def userdefined():
return render_template("userdefined.html",s="abcdefg")
userdefined.html內容如下:
{{s|reverse}}
請大家自行嘗試該模板的渲染結果。