標籤:style io os 使用 ar java for strong sp
節選自PartI Chapter3,這個chapter主要講模板工作原理,這裡講的就是Jinja2這個模板,另外還提到了Flask-Bootstrap及Flask-Moment兩個外掛程式,前者對Flask使用Bootstrap做了些封裝,後者對moment.js做了些封裝。內容較多,估計分開搞。
模板存在的意義
可維護性高的代碼是結構良好且整潔的。
當使用者在網站註冊一個賬戶時,他在表單裡填入郵箱跟密碼,並點擊提交按鈕。在server端就收到一個包含這些資料的request,再由Flask分發到相應的視圖函數處理。視圖函數這裡就產生兩個任務,首先在資料庫增加新使用者,然後給使用者的瀏覽器返回一個response。這兩個任務可分別稱為商務邏輯(business logic)和報告邏輯(presentation logic)。
將這兩個邏輯混在一起可能導致代碼混亂,難以維護。可以想象在代碼裡直接產生複雜HTML頁面再嵌入資料的複雜度。將報告邏輯移入模板處理,可以提高應用的可維護性。
模板其實就是一個文本,裡面有一些包含變數的動態部分,這些變數的內容在有request上下文時才能知道。將這些變數替換成實際值,最終產生一個response字串的過程叫渲染。Flask使用強大的Jinja2來處理渲染模板任務。
Jinja2模板引擎
一個簡單的Jinja2模板,index.html:
<h1>Hello World!</h1>
就是一個固定的字串,直接返回這個字串。再看稍複雜的, user.html:
<h1>Hello, {{ name }}!</h1>
裡面帶有一個動態部分,name是個變數,response會隨之改變。
渲染模板
Flask預設到應用根目錄下的templates檔案夾下找相應模板,先把上面的兩個簡單模板放到這個檔案夾下,然後修改之前寫的hello.py:
from flask import Flask, render_template# ...@app.route(‘/index‘)def index(): return render_template(‘index.html‘)@app.route(‘/user/<name>‘)def user(name): return render_template(‘user.html‘, name=name)
註:上面是github上的3a tag下代碼
Flask提供的render_template函數可以配合Jinja2使用,它的第一個參數是模板名,之後的參數都是模板中的變數值,以key/value形式傳入。key就是在模板中寫的變數名。
模板中的變數
{{ name }}這種結構表示引用了一個變數,它告訴模板引擎,裡面的值需要在模板被渲染時提供的資料中擷取。
Jinja2可以識別多種類型,甚至包括列表,字典和對象。如:
<p>A value from a dictionary: {{ mydict[‘key‘] }}.</p><p>A value from a list: {{ mylist[3] }}.</p><p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p><p>A value from an object‘s method: {{ myobj.somemethod() }}.</p>
變數可以通過過濾器進一步修改,過濾器放在變數後面以分隔字元隔開。比如下面模板表示變數被首字母大寫化:
Hello, {{ name|capitalize }}
常用過濾器如下:
- safe 不對傳入值轉義
- capitalize 傳入值首字母大寫,其他小寫
- lower 傳入值全部轉為大寫
- upper 傳入值全部轉為小寫
- title 傳入值中每個字首大寫
- trim 傳入值前後空格刪除
- striptags 傳入值內所有HTML標籤刪除
重點提下safe,出於安全性考慮,Jinja2預設把變數中的值進行轉義,比如值為<h1>Hello</h1>,就會被渲染為<h1>Hello</h1>,這就導致內嵌標籤失效,如果需要顯示內嵌標籤,就用safe過濾器。
註:對於無法信任的位置,不要使用safe,比如使用者填入的表單值。
更多過濾器可以參考Jinja2官方文檔
控制結構
Jinja2提供了幾種控制結構,來改變模板的渲染流程。下面介紹幾種比較常用的。
模板中加入條件控制:
{% if user %} Hello, {{ user }}!{% else %} Hello, Stranger!{% endif %}
模板中對一個列表元素進行迴圈:
<ul> {% for comment in comments %} <li>{{ comment }}</li> {% endfor %}</ul>
Jinja2支援宏,類似於Pyhton代碼裡的函數:
{% macro render_comment(comment) %} <li>{{ comment }}</li>{% endmacro %}<ul> {% for comment in comments %} {{ render_comment(comment) }} {% endfor %}</ul>
想增加宏的重用性,可以把宏放入單獨檔案中,然後在模板中引入:
{% import ‘macros.html‘ as macros %}<ul> {% for comment in comments %} {{ macros.render_comment(comment) }} {% endfor %}</ul>
模板中的一些代碼在不同地方重複出現的話,把這部分單獨儲存成一個檔案,在需要的地方include進來,避免重複書寫:
{% include ‘common.html‘ %}
增加重用性的另一個重要方式,是模板繼承,類似於Python代碼中類的繼承。先定義一個基本模板:
`base.html`:<html><head> {% block head %} <title>{% block title %}{% endblock %} - My Application</title> {% endblock %}</head><body> {% block body %} {% endblock %}</body></html>
在block標籤中的元素可以在繼承的模板中被改變。上面出現了名為head,title,body的區塊。注意title被定義在了head中。看一個繼承這個模板的例子:
{% extends "base.html" %}{% block title %}Index{% endblock %}{% block head %} {{ super() }} <style> </style>{% endblock %}{% block body %}<h1>Hello, World!</h1>{% endblock %}
extends關鍵字聲明這個模板是繼承自base.html,之後是三個新定義的區塊,區塊名與定義順序對應於基本模板。注意在基本模板中head區塊是有內容的,使用super()方法可以保留原有內容。
後續會有更多關於模板的真實使用方式。
Flask Web Development - Flask 模板1 - 模板機制&Jinja2引擎