1. 程式人生 > >邊做邊學Python Flask Web開發(5)-- 使用Jinjia2模板(中)

邊做邊學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}}

請大家自行嘗試該模板的渲染結果。