python Jinja2模板
模板在Python的web開發中應用廣泛,能夠有效的將業務邏輯和頁面邏輯分離。
模板包含的是一個響應文本的文件,包含用佔位變量表示的動態部分,其具體值只在請求的上下文中才能知道。使用真實的值替換變量,再返回最終得到的響應字符串,這一過程稱爲渲染。簡單來說,渲染就是使用真實的值替換變量,再返回最終得到的響應字符串。
Jinja2語法入門
Jinja2是Flask作者開發的一個模板系統。Flask是一個使用Python編寫的輕量級Web應用框架。安裝Flask,Jinja2也會隨之安裝,也可以單獨安裝Jinja2
pip install flask
or
pip install jinja2
Jinja2模板引擎之所以廣泛使用,是因爲它具有以下優點:
- Jinja2更加靈活,提供了控制結構、表達式和繼承等
- Jinja2提供了僅有的控制結構,不允許在模板中編寫太多的業務邏輯,避免了工程師亂用行爲。
- Jinja2模板的可讀性很好
1 語法塊
jinja2可以應用於任何基於文本的格式,如HTML、XML。Jinja2使用大括號的方式表示Jinja2的語法。
在Jinja2中,存在三種語法:
控制結構:{% %}
變量取值:{{ }}
註釋:{# #}
for循環:
{% for user in users %}
{% endfor%}
if循環:
{% if users %}
<ul>
{% for user in users %}
<li>{{ user.username }}</li>
{% endfor%}
</ul>
{% endif %}
2 變量
Jinja2模板中使用{{}}語法表示一個變量,是一種特殊的佔位符,告訴模板引擎這個位置的值在渲染模板時獲取。Jinja2識別所有的Python數據類型,甚至是一些複雜的類型,如列表、字典、對象等。
<p>A value from a dictionary: {{ mydict['key']}}</p>
<p>A value from an object's method: {{myobject.somemethod()}}</p>
3 Jinja2中的過濾器
變量可以通過過濾器進行修改,過濾器可以理解爲是Jinja2裏面的內置函數和字符串處理函數。例如,存在一個名爲lower的過濾器,作用與字符串對象的lower方法一模一樣。
常用的Jinja2過濾器:
字符串操作
過濾器名 | 說明 |
---|---|
safe | 渲染時不轉義 |
capitalize | 把值的首字母轉換成大寫,其他字母轉換成小寫 |
lower | 把值轉換成小寫形式 |
upper | 把值轉換成大寫形式 |
reverse | 字符串反轉 |
title | 把值中每個單詞的首字母都轉換成大寫 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML標籤都刪掉 |
join | 拼接多個值爲字符串 |
replace | 替換字符串的值 |
round | 默認對值進行四捨五入 |
int | 把值轉換成整型 |
format | 格式化輸出 |
truncate | 字符串截斷 |
列表操作
過濾器 | 說明 |
---|---|
first | 取第一個元素 |
last | 取最後一個元素 |
length | 獲取列表長度 |
sum | 列表求和 |
sort | 列表排序 |
過濾器與變量用管道(|)分割,多個過濾器可以鏈式調用,前一個過濾器的輸出會作爲後一個過濾器的輸入。
{{ "hello world" | replace("hello","goodbye")}}
-> goodbye world
{{ 42.55 | round | int }}
-> 43
4 Jinja2的控制結構
Jinja2中if語句類似於Python中的if語句,需要使用endif語句作爲條件判斷的結束.
{% if a>2 %}
a大於2
{% elif 1<a<=2%}
a大於1小於2
{% else %}
a小於1
{% endif %}
5 Jinja2的for循環
Jinja2中的for語句可用於迭代Python的數據類型,包括列表、元組和字典。
迭代列表:
<ul>
{% for user in users %}
<li>{{ user.username }}</li>
{% endfor %}
</ul>
遍歷字典:
dl 標籤定義了定義列表(definition list)。
dl 標籤用於結合 dt(定義列表中的項目)和 dd(描述列表中的項目)
<dl>
{% for key,value in d.iteritems() %}
<dt>{{ key }}</dt>
<dd>{{ value }}</dd>
{% endfor %}
</dl>
除了基本的for循環使用以外,Jinja2還提供了一些特殊的變量,不用定義可以直接使用這些變量。
for循環中的特殊變量
變量 | 描述 |
---|---|
loop.index | 當前循環迭代的次數(從1開始) |
loop.index() | 當前循環迭代的次數(從0開始) |
loop.revindex | 到循環結束的次數(從1開始) |
loop.revindex() | 到循環結束的次數(從0開始) |
loop.first | 如果是第一次迭代爲True,否則爲False |
loop.last | 如果是最後一次迭代,爲True,否則爲False |
loop.length | 序列中的項目數 |
loop.cycle | 在一串序列間取值的輔助函數 |
示例如下:保存聯繫人信息,字典的key是聯繫人的名字,字典的value是聯繫人的電話。第一列是序號
{% for key,value in data.iteritems() %}
<tr class="info">
<td>{{ loop.index }}</td>
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
{% endfor%}
6 Jinja2的宏
宏類似於編程語言中的函數,用於將行爲抽象成可重複調用的代碼塊。與函數一樣,宏分爲定義和調用。
聲明宏如下:
使用macro關鍵字定義一個宏,input是宏的名稱,有三個參數,分別是name,type和value。使用endmacro結束宏的定義。
{% macro input(name,type='text',value='') %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}
宏的調用如下,與函數調用類似:
<p>{{ input('username',value='user') }}</p>
<p>{{ input('password','password') }}</p>
<p>{{ input('submit','submit','Submit') }}</p>
7 Jinja2的繼承和Super函數
Jinja2中最強大的部分就是模板繼承。模板繼承允許構建一個包含站點共同元素的基本模板骨架,並定義子模板可以覆蓋的塊。
使用{% block name %}的方式定義三個塊,這些塊可以在子模板中進行替換或調用。
父模板:base.html
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %}-Web基礎模板</title>
{% endblock %}
</head>
<body>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
子模板:index.html
使用{% extends ”base.html" %}繼承base.html,繼承以後,base.html中的所有內容都會在index.html中展現。在index.html中,重新定義了title和content這兩個塊的內容
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important"> 個人博客 </p>
{ % endblock %}
8.Jinja2的其他運算
Jinja2可以對變量進行算數操作、比較操作、邏輯操作。
算數運算 | ± */ // % ** |
---|---|
比較運算 | == != > >= < <= |
邏輯運算 | not and or |
加載模板
想要在模板中使用Jinja2,只需要使用Flask包下的render_template函數訪問模板即可。
Jinja2模塊中有一個名爲Environment的類,這個類的實例用於存儲配置和全局對象,然後從文件系統或其他位置加載模板。
方法一:包加載器
創建Environment對象和包加載器,該加載器會在yourapplication這個python包的templates目錄下查找模板。
from jinja2 import Environment,PackageLoader
env = Environment(loader=PackageLoader('yourapplication','templates'))
接下來,只需要以模板的名字爲參數調用Environment.get_template方法即可。該方法返回一個模板,最後使用模板的render方法進行渲染。
template = env.get_template("mytemplate.html")
print(template.render(the='variable',go='here'))
方法二:文件加載器
文件系統加載器可以直接訪問系統中的文件
import os
from jinja2 import Environment,FileSystemLoader
def render(tpl_path,**kwargs):
path,filename = os.path.split(tpl_path)
env = Environment(loader=FileSystemLoader(path or './'))
template = env.get_template(filename)
return template.render(**kwargs)
模板渲染示例:
simple.html
使用for循環遍歷一個列表,列表中的每一項是一個字典。字典中包含了文字和鏈接。將使用字典中的數據渲染HTML超鏈接。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title | trim }}</title>
</head>
<body>
<p>{{ content }}</p>
<ul id="navigation">
{% for item in items %}
<li><a href="{{item.href}}">{{ item['caption'] }}</a></li>
{% endfor %}
</ul>
</body>
</html>
使用flask下的render_template方法渲染模板
from flask import Flask
from flask import render_template
app = Flask(__name__)
app.config["SECRET_KEY"] = "XXXXDWEFS"
@app.route('/simple/')
def test_simple():
title = "測試jinjia2模板 "
items = [{'herf':'https://www.baidu.com/','caption':'百度'},{'herf':'test.www.com','caption':'個人博客'}]
content = "網站跳轉鏈接如下:"
return render_template('simple.html',title=title,items=items,content=content)
if __name__ == "__main__":
app.run(debug=True)
繼承功能示例
base.html
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<h4>{% block title %}{% endblock %}-Web基礎模板</h4>
{% endblock %}
<h4>Jinjia2模板示例</h4>
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="footer">
{% block footer %}
{% endblock %}
</div>
</body>
</html>
index.html
{% extends "base.html" %}
<!-- 標題模塊被重載 -->
{% block title %}Index{% endblock %}
<!-- head模塊被重載,並且使用super繼承了base.html中head的內容 -->
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
<!-- 覆蓋了content模塊 -->
{% block content %}
<h1>歡迎訪問</h1>
<p class="important"> 個人博客 </p>
{% endblock %}
from flask import Flask
from flask import render_template
app = Flask(__name__)
app.config["SECRET_KEY"] = "XXXXDWEFS"
@app.route('/index/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)