前言
來(lái)啦老鐵!
筆者近期在工作中遇到將測(cè)試數(shù)據(jù)可視化的需求,且在Python語(yǔ)言背景下,當(dāng)時(shí)借用的是團(tuán)隊(duì)既有經(jīng)驗(yàn),即:
-
模板引擎技術(shù)
而模板引擎使用:Jinja2
看過(guò)筆者的Spring Boot全家桶系列文章的同學(xué)一定不會(huì)陌生,我們?cè)谖恼?a href="http://www.itdecent.cn/p/3037e5963dd4" target="_blank">Spring Boot視圖技術(shù)中,一起學(xué)習(xí)了java體系下的視圖技術(shù)(模板引擎技術(shù)),咱們今天也來(lái)學(xué)習(xí)學(xué)習(xí)Python體系下的模板引擎技術(shù)吧!
學(xué)習(xí)路徑
- 常見(jiàn)的Python模板引擎有哪些?
- Jinja2簡(jiǎn)介;
- Jinja2入門(mén)使用;
- Jinja2的基礎(chǔ)知識(shí)點(diǎn);
1. 常見(jiàn)的Python模板引擎有哪些?
首先我們來(lái)看看網(wǎng)上的大佬們都玩過(guò)哪些Python的模板引擎吧:
- pyTemplate
- pyTenjin
- Tornado.template
- PyJade
- Genshi
- Django
- Smarty
- Mako
- Jinja2
- 等。
這么多?筆者只聽(tīng)過(guò)Django和Jinja2,孤陋寡聞了,有興趣的朋友請(qǐng)移步百度~
2. Jinja2簡(jiǎn)介;
來(lái)源:https://www.cnblogs.com/yanjiayi098-001/p/11701150.html
1). Jinja2介紹:
jinja2是Flask作者開(kāi)發(fā)的一個(gè)模板系統(tǒng),起初是仿django模板的一個(gè)模板引擎,為Flask提供模板支持,由于其靈活,快速和安全等優(yōu)點(diǎn)被廣泛使用。
2). Jinja2的優(yōu)點(diǎn):
- 相對(duì)于Template,jinja2更加靈活,它提供了控制結(jié)構(gòu),表達(dá)式和繼承等;
- 相對(duì)于Mako,jinja2僅有控制結(jié)構(gòu),不允許在模板中編寫(xiě)太多的業(yè)務(wù)邏輯;
- 相對(duì)于Django模板,jinja2性能更好;
- Jinja2模板的可讀性很棒。
3. Jinja2入門(mén)使用;
話不多說(shuō),咱直接開(kāi)整,代碼倉(cāng)庫(kù):
我們直接開(kāi)始擼一個(gè)簡(jiǎn)單的渲染例子,當(dāng)然,在使用Jinja2前,需要安裝Jinja2喲:
pip3 install jinja2
1). 創(chuàng)建模板文件;
模板文件即html文件,我們?cè)陧?xiàng)目?jī)?nèi)創(chuàng)建一個(gè)python包,如resources包,在resources包內(nèi)創(chuàng)建一個(gè)模板文件夾templates,用于存放Jinja模板,最后在templates文件夾下創(chuàng)建一模板文件如:jinja2_demo_1.html;
2). 編寫(xiě)模板文件;
在jinja2_demo_1.html文件中,編寫(xiě)簡(jiǎn)單的Jinja模板,代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jinja2-demo-1</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>INDEX</th>
<th>STATUS</th>
<th>MESSAGE</th>
<th>CREATED_WHEN</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{index}}</td>
<td>{{status}}</td>
<td>{{message}}</td>
<td>{{created_when}}</td>
</tr>
</tbody>
</table>
</body>
</html>
我們會(huì)發(fā)現(xiàn),模板中沒(méi)有寫(xiě)死的數(shù)據(jù),而是以{{}}符號(hào)包裹變量,如果這時(shí)候直接瀏覽器打開(kāi)resources/templates/jinja2_demo_1.html文件,效果為:

沒(méi)錯(cuò),就是個(gè)模板而已,沒(méi)有真實(shí)值。接下來(lái)我們就來(lái)將{{}}符號(hào)包裹變量變成我們想展示的值吧!
3). 創(chuàng)建模板渲染邏輯處理類(lèi);
在項(xiàng)目根目錄下創(chuàng)建一個(gè)python包,如utils包,在包內(nèi)創(chuàng)建一個(gè)python類(lèi),如reportUtil.py,類(lèi)中編寫(xiě)一簡(jiǎn)單的模板渲染邏輯,如下:
#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
__author__ = "diren"
__date__ = "2021-01-03 15:50"
import os
import time
from jinja2 import Environment, PackageLoader
class ReportUtil:
def __init__(self):
pass
def create_jinja2_demo_1_html(self):
index = 1
status = "成功"
message = "這是一個(gè)測(cè)試文本"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = "jinja2_demo_1.html"
template = env.get_template(template_name)
html = template.render(index=index, message=message, created_when=created_when, status=status)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
if __name__ == "__main__":
ReportUtil().create_jinja2_demo_1_html()
這里稍微講解一下我們的目的:
- 我們希望通過(guò)reportUtil.py,將一組數(shù)據(jù)渲染進(jìn)resources/templates/jinja2_demo_1.html文件中表格的第一行;
- 渲染的數(shù)據(jù)為:
index = 1
status = "成功"
message = "這是一個(gè)測(cè)試文本"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- 渲染后的文件存儲(chǔ)于resources/output/jinja2_demo_1.html中,
渲染預(yù)期為一個(gè)簡(jiǎn)單表格;
4). 項(xiàng)目整體結(jié)構(gòu);

5). 演示;
運(yùn)行reportUtil.py,我們能看到resources包下生成了一個(gè)output文件夾,output文件夾下有一個(gè)html文件:jinja2_demo_1.html,該文件就是我們?cè)趓eportUtil.py渲染出來(lái)的靜態(tài)html文件:

瀏覽器打開(kāi)resources/output/jinja2_demo_1.html文件:

嗯,沒(méi)錯(cuò),原來(lái){{}}符號(hào)包裹的變量,均變成我們r(jià)eportUtil.py代碼中想渲染的真實(shí)值了,渲染演示成功!是不是很簡(jiǎn)單呀!
上述,演示了一個(gè)非常簡(jiǎn)單的Jinja2使用方法,接下來(lái)我們一起來(lái)邊學(xué)習(xí)Jinja2的常用功能,邊碼代碼、邊演示、邊學(xué)習(xí)吧!
4. Jinja2的基礎(chǔ)知識(shí)點(diǎn);
這里羅列一下基礎(chǔ)知識(shí)點(diǎn):
- 基本語(yǔ)法;
- 運(yùn)算符;
- 轉(zhuǎn)義方法;
- 測(cè)試器;
- 如何在模版頁(yè)面中引入靜態(tài)文件?
- 過(guò)濾器;
- 宏;
- 模板繼承;
1). 基本語(yǔ)法;
注釋 {#...#}
例如:{#這是一個(gè)注釋#},這一行代碼是不會(huì)被渲染、處理的,起注釋作用;變量取值 {{...}}
如上面的例子, {{}}是占位符,Jinja2渲染時(shí)會(huì)將這些占位符替換成真實(shí)值。它支持python中的所有數(shù)據(jù)類(lèi)型,如字符串、字典、列表等。
- 控制結(jié)構(gòu) {% ... %}
該符號(hào)包裹的內(nèi)容表示控制結(jié)構(gòu),如分支、循環(huán),我們來(lái)演示一下:
(1). if語(yǔ)句:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jinja2-demo-1</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>INDEX</th>
<th>STATUS</th>
<th>MESSAGE</th>
<th>CREATED_WHEN</th>
</tr>
</thead>
{#這是一個(gè)注釋#}
<tbody>
{% if index==1 %}
<tr>
<td>{{index}}</td>
<td>{{status}}</td>
<td>{{message}}</td>
<td>{{created_when}}</td>
</tr>
{% elif index==2 %}
<tr>
<td>{{index}}</td>
<td>{{status}}</td>
</tr>
{% else %}
<tr>
<td>{{index}}</td>
<td>{{status}}</td>
<td>{{message}}</td>
</tr>
{% endif %}
</tbody>
</table>
</body>
</html>
很簡(jiǎn)單,當(dāng)index為1,2,其他值時(shí),表格顯示的內(nèi)容略有差異:



(2). for語(yǔ)句:
我們使用for語(yǔ)句,演示渲染一個(gè)含有多條數(shù)據(jù)的表格,并且為了演示效果,我順便從網(wǎng)上找了個(gè)樣式,稍作調(diào)整,創(chuàng)建新的模板文件jinja2_demo_2.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jinja2-demo-2</title>
</head>
<body>
<title>{{title}}</title>
<div class="card">
<div class="card-title">
<span style="color: #ffffff; font-size: 28px; font-weight: 700">{{title}}</span>
</div>
<div class="card-content">
<div>最終結(jié)果:{{ status }}</div>
<div>發(fā)布日期:{{ created_when }}</div>
</div>
</div>
<br>
<table class="pure-table pure-table-bordered">
<thead>
<tr>
<th>INDEX</th>
<th>STATUS</th>
<th>MESSAGE</th>
<th>CREATED_WHEN</th>
</tr>
</thead>
<tbody>
{% for item in details %}
<tr class="{{ loop.cycle('odd', 'even') }}">
<td>{{item.index}}</td>
<td>{{item.status}}</td>
<td>{{item.message}}</td>
<td>{{item.created_when}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
<style type="text/css">
.odd {
}
.even {
background-color: #F5F5F5;
}
.card-title {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #B0C4DE;
border-color: #e7eaec;
-webkit-border-image: none;
-o-border-image: none;
border-image: none;
border-style: solid solid none;
border-width: 4px 0 0;
color: inherit;
margin-bottom: 0;
padding: 14px 15px 7px;
min-height: 48px;
}
.card-content {
background-color: #fff;
color: inherit;
padding: 15px 20px 20px;
border-color: #e7eaec;
-webkit-border-image: none;
-o-border-image: none;
border-image: none;
border-style: solid solid none;
border-width: 1px 0
}
.card-content div {
padding: 6px;
}
.card {
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
text-align: left;
}
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 10px;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
max-width: 100%;
margin-bottom: 20px;
}
td,th {
padding: 0;
}
.pure-table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 1px solid #cbcbcb;
}
.pure-table caption {
color: #000;
font: italic 85%/1 arial,sans-serif;
padding: 1em 0;
text-align: center;
}
.pure-table td,.pure-table th {
border-left: 1px solid #cbcbcb;
border-width: 0 0 0 1px;
font-size: inherit;
margin: 0;
overflow: visible;
padding: .5em 1em;
}
.pure-table thead {
background-color: #00BFFF;
color: #000;
text-align: left;
vertical-align: bottom;
}
.pure-table td {
background-color: transparent;
}
.pure-table-bordered td {
border-bottom: 1px solid #cbcbcb;
}
.pure-table-bordered tbody>tr:last-child>td {
border-bottom-width: 0;
}
</style>
reportUtil.py中也新增一渲染方法create_jinja2_demo_2_report,代碼如下:
#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
__author__ = "diren"
__date__ = "2021-01-03 15:50"
import os
import time
from jinja2 import Environment, PackageLoader
class ReportUtil:
def __init__(self):
pass
def create_jinja2_demo_1_html(self):
index = 1
status = "成功"
message = "這是一個(gè)測(cè)試文本"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = "jinja2_demo_1.html"
template = env.get_template(template_name)
html = template.render(index=index, message=message, created_when=created_when, status=status)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
def create_jinja2_demo_2_html(self):
title = "測(cè)試報(bào)告"
status = "失敗"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
details = [{
"status": "成功",
"message": "測(cè)試文本1",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 2,
"status": "失敗",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 3,
"status": "成功",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}]
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'jinja2_demo_2.html'
template = env.get_template(template_name)
html = template.render(title=title, status=status, created_when=created_when, details=details)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
if __name__ == "__main__":
ReportUtil().create_jinja2_demo_1_html()
ReportUtil().create_jinja2_demo_2_html()
運(yùn)行reportUtil.py后:


這樣,我們順利將多條數(shù)據(jù)渲染進(jìn)模板進(jìn)行展示,數(shù)據(jù)為:
title = "測(cè)試報(bào)告"
status = "失敗"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
details = [{
"index": 1,
"status": "成功",
"message": "測(cè)試文本1",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 2,
"status": "失敗",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 3,
"status": "成功",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}]
其中表格主題數(shù)據(jù)為:details;
我們還可以在循環(huán)中加入條件語(yǔ)句,如:
<tbody>
{% for item in details %}
<tr class="{{ loop.cycle('odd', 'even') }}">
<td>{{item.index}}</td>
<td>{{item.status}}</td>
<td>{{item.message}}</td>
<td>{{item.created_when}}</td>
</tr>
{% else %}
<tr>
<td>no data found</td>
<td>no data found</td>
<td>no data found</td>
<td>no data found</td>
</tr>
{% endfor %}
</tbody>
則當(dāng)details為空時(shí),表格會(huì)展示一行no data found的數(shù)據(jù);

我們也可以遍歷python字典進(jìn)行展示,如:
模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jinja2-demo-3</title>
</head>
<body>
<title>{{title}}</title>
<div class="card">
<div class="card-title">
<span style="color: #ffffff; font-size: 28px; font-weight: 700">{{title}}</span>
</div>
<div class="card-content">
<div>最終結(jié)果:{{ status }}</div>
<div>發(fā)布日期:{{ created_when }}</div>
</div>
</div>
<br>
<table class="pure-table pure-table-bordered">
<thead>
<tr>
<th>KEY</th>
<th>VALUE</th>
</tr>
</thead>
<tbody>
{% for key,value in test_dict.items() %}
<tr class="{{ loop.cycle('odd', 'even') }}">
<td>{{key}}</td>
<td>{{value}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
<style type="text/css">
.odd {
}
.even {
background-color: #F5F5F5;
}
.card-title {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #B0C4DE;
border-color: #e7eaec;
-webkit-border-image: none;
-o-border-image: none;
border-image: none;
border-style: solid solid none;
border-width: 4px 0 0;
color: inherit;
margin-bottom: 0;
padding: 14px 15px 7px;
min-height: 48px;
}
.card-content {
background-color: #fff;
color: inherit;
padding: 15px 20px 20px;
border-color: #e7eaec;
-webkit-border-image: none;
-o-border-image: none;
border-image: none;
border-style: solid solid none;
border-width: 1px 0
}
.card-content div {
padding: 6px;
}
.card {
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
text-align: left;
}
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 10px;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
max-width: 100%;
margin-bottom: 20px;
}
td,th {
padding: 0;
}
.pure-table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 1px solid #cbcbcb;
}
.pure-table caption {
color: #000;
font: italic 85%/1 arial,sans-serif;
padding: 1em 0;
text-align: center;
}
.pure-table td,.pure-table th {
border-left: 1px solid #cbcbcb;
border-width: 0 0 0 1px;
font-size: inherit;
margin: 0;
overflow: visible;
padding: .5em 1em;
}
.pure-table thead {
background-color: #00BFFF;
color: #000;
text-align: left;
vertical-align: bottom;
}
.pure-table td {
background-color: transparent;
}
.pure-table-bordered td {
border-bottom: 1px solid #cbcbcb;
}
.pure-table-bordered tbody>tr:last-child>td {
border-bottom-width: 0;
}
</style>
其中,關(guān)鍵代碼:{% for key,value in test_dict.items() %}...{% endfor %}
reportUtil.py中新增create_jinja2_demo_3_html方法:
#!/usr/local/bin/python3
# -*- coding:utf-8 -*-
__author__ = "diren"
__date__ = "2021-01-03 15:50"
import os
import time
from jinja2 import Environment, PackageLoader
class ReportUtil:
def __init__(self):
pass
def create_jinja2_demo_1_html(self):
index = 1
status = "成功"
message = "這是一個(gè)測(cè)試文本"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = "jinja2_demo_1.html"
template = env.get_template(template_name)
html = template.render(index=index, message=message, created_when=created_when, status=status)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
def create_jinja2_demo_2_html(self):
title = "測(cè)試報(bào)告"
status = "失敗"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
details = [{
"status": "成功",
"message": "測(cè)試文本1",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 2,
"status": "失敗",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}, {
"index": 3,
"status": "成功",
"message": "測(cè)試文本2",
"created_when": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}]
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'jinja2_demo_2.html'
template = env.get_template(template_name)
html = template.render(title=title, status=status, created_when=created_when, details=details)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
def create_jinja2_demo_3_html(self):
title = "人員信息"
status = "采集成功"
created_when = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
test_dict = {
"name": "dylanz",
"gender": "male",
"age": 18,
"professional": "TA"
}
env = Environment(loader=PackageLoader('resources', 'templates'))
template_name = 'jinja2_demo_3.html'
template = env.get_template(template_name)
html = template.render(title=title, status=status, created_when=created_when, test_dict=test_dict)
current_dir = os.getcwd()
output_dir = os.path.join(current_dir, "../resources/output/")
if not os.path.exists(output_dir):
os.mkdir(output_dir)
os.chdir(output_dir)
fo = open(template_name, "w")
fo.writelines(html)
fo.close()
os.chdir(current_dir)
print(f"create {template_name}:", "完成")
if __name__ == "__main__":
ReportUtil().create_jinja2_demo_1_html()
ReportUtil().create_jinja2_demo_2_html()
ReportUtil().create_jinja2_demo_3_html()
效果:

Jinja2中for循環(huán)內(nèi)置常量
細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),在for循環(huán)中,我們使用loop.cycle來(lái)交替使用單元格樣式'odd', 'even',loop.cycle為Jinja2中循環(huán)計(jì)數(shù)內(nèi)置變量,而Jinja2還擁有其他循環(huán)內(nèi)置常量,有:

篇幅有限,請(qǐng)讀者自行了解、嘗試哈!
2). 運(yùn)算符;
+號(hào)運(yùn)算符:可以完成數(shù)字相加,字符串相加,列表相加。但是并不推薦使用+運(yùn)算符來(lái)操作字符串,字符串相加應(yīng)該使用~運(yùn)算符。
-號(hào)運(yùn)算符:只能針對(duì)兩個(gè)數(shù)字相減。
/號(hào)運(yùn)算符:對(duì)兩個(gè)數(shù)進(jìn)行相除。
%號(hào)運(yùn)算符:取余運(yùn)算。
*號(hào)運(yùn)算符:乘號(hào)運(yùn)算符,并且可以對(duì)字符進(jìn)行相乘。
**號(hào)運(yùn)算符:次冪運(yùn)算符,比如2**3=8。
in操作符:跟python中的in一樣使用,比如{{1 in [1,2,3]}}返回true。
~號(hào)運(yùn)算符:拼接多個(gè)字符串,比如{{"Hello" ~ "World"}}將返回HelloWorld。
3). 轉(zhuǎn)義方法;
開(kāi)啟轉(zhuǎn)義:
在模板渲染字符串的時(shí)候,字符串有可能包括一些非常危險(xiǎn)的字符比如<、>等,這些字符會(huì)破壞掉原來(lái)HTML標(biāo)簽的結(jié)構(gòu),更嚴(yán)重的可能會(huì)發(fā)生XSS跨域腳本攻擊,因此如果碰到<、>這些字符的時(shí)候,應(yīng)該轉(zhuǎn)義成HTML能正確表示這些字符的寫(xiě)法。
- 對(duì)引用的變量值進(jìn)行轉(zhuǎn)義:{{ 變量名|e }}或{{ 變量名|escape }}
- 將代碼段進(jìn)行自動(dòng)轉(zhuǎn)義:{%autoescape true%}...{%endautoescape%},如:
{% autoescape true %}
<p>自動(dòng)轉(zhuǎn)義已開(kāi)啟</p>
<p>{{ 變量引用值會(huì)被自動(dòng)轉(zhuǎn)義 }}</p>
{% endautoescape %}
關(guān)閉轉(zhuǎn)義:
- 對(duì)引用的變量值關(guān)閉轉(zhuǎn)義:{{變量名|safe }}
- 將代碼段關(guān)閉自動(dòng)轉(zhuǎn)義:{%autoescape false%}...{%endautoescape%},如:
{% autoescape false %}
<p>自動(dòng)轉(zhuǎn)義已關(guān)閉</p>
<p>{{ 變量引用值不會(huì)被自動(dòng)轉(zhuǎn)義 }}</p>
{% endautoescape %}
4). 測(cè)試器;
測(cè)試器主要用來(lái)判斷一個(gè)值是否滿(mǎn)足某種類(lèi)型,語(yǔ)法是:if...is...,例如:
{% if 變量名 is string%}
字符串變量的值為: {{ 變量名 }}
{% else %}
不是字符串變量
{% endif %}
其中string就是測(cè)試器。
Jinja2中測(cè)試器有:
- callable:是否可調(diào)用;
- defined:是否已經(jīng)被定義了;
- escaped:是否已經(jīng)被轉(zhuǎn)義了;
- upper:是否全是大寫(xiě);
- lower:是否全是小寫(xiě);
- string:是否是一個(gè)字符串;
- sequence:是否是一個(gè)序列;
- number:是否是一個(gè)數(shù)字;
- odd:是否是奇數(shù);
- even:是否是偶數(shù);
5). 如何在模版頁(yè)面中引入靜態(tài)文件?
在Jinja中加載靜態(tài)文件只需要通過(guò)url_for全局函數(shù)就可以實(shí)現(xiàn),例如引入static目錄下的style.css文件:
<style type="text/css" href="{{ url_for('static',filename='style.css') }}"/>
該用法需要在Flask框架下,指定靜態(tài)文件路徑方可,此處開(kāi)卷有益~
6). 過(guò)濾器;
前面提到的幾個(gè)用法:{{ 變量名|e }}或{{ 變量名|escape }}、{{變量名|safe }},這些其實(shí)是利用了Jinja2中的過(guò)濾器功能,過(guò)濾器是通過(guò)“|”符號(hào)進(jìn)行使用的,符號(hào)前為過(guò)濾器輸入,符號(hào)后為過(guò)濾器函數(shù)、方法、規(guī)則,意思是變量值不直接進(jìn)行渲染,而是根據(jù)過(guò)濾器函數(shù)的規(guī)則進(jìn)行轉(zhuǎn)換后,再進(jìn)行渲染。
過(guò)濾器函數(shù)可將變量值轉(zhuǎn)成絕對(duì)值、大小寫(xiě)、轉(zhuǎn)義等再進(jìn)行渲染,Jinja2擁有許多過(guò)濾器規(guī)則,我們一起來(lái)學(xué)習(xí)一下吧:
來(lái)源:https://www.cnblogs.com/songyifan427/p/10144506.html
- abs(value):返回一個(gè)數(shù)值的絕對(duì)值,示例:-1|abs;
- default(value,default_value,boolean=false):如果當(dāng)前變量沒(méi)有值,則會(huì)使用參數(shù)中的值來(lái)代替。示例:name|default('xiaotuo')——如果name不存在,則會(huì)使用xiaotuo來(lái)替代;boolean=False默認(rèn)是在只有這個(gè)變量為undefined的時(shí)候才會(huì)使用default中的值,如果想使用python的形式判斷是否為false,則可以傳遞boolean=true。也可以使用or來(lái)替換;
- escape(value)或e:轉(zhuǎn)義字符,會(huì)將<、>等符號(hào)轉(zhuǎn)義成HTML中的符號(hào)。示例:content|escape或content|e;
- first(value):返回一個(gè)序列的第一個(gè)元素。示例:names|first;
- format(value,*arags,**kwargs):格式化字符串。比如:
{{ "%s" - "%s"|format('Hello?',"Foo!") }}
將輸出:Helloo? - Foo!
last(value):返回一個(gè)序列的最后一個(gè)元素。示例:names|last;
length(value):返回一個(gè)序列或者字典的長(zhǎng)度。示例:names|length;
join(value,d=u''):將一個(gè)序列用d這個(gè)參數(shù)的值拼接成字符串;
safe(value):如果開(kāi)啟了全局轉(zhuǎn)義,那么safe過(guò)濾器會(huì)將變量關(guān)掉轉(zhuǎn)義。示例:content_html|safe;
int(value):將值轉(zhuǎn)換為int類(lèi)型;
float(value):將值轉(zhuǎn)換為float類(lèi)型;
lower(value):將字符串轉(zhuǎn)換為小寫(xiě);
upper(value):將字符串轉(zhuǎn)換為小寫(xiě);
replace(value,old,new): 替換將old替換為new的字符串;
truncate(value,length=255,killwords=False):截取length長(zhǎng)度的字符串;
striptags(value):刪除字符串中所有的HTML標(biāo)簽,如果出現(xiàn)多個(gè)空格,將替換成一個(gè)空格;
trim:截取字符串前面和后面的空白字符;
string(value):將變量轉(zhuǎn)換成字符串;
wordcount(s):計(jì)算一個(gè)長(zhǎng)字符串中單詞的個(gè)數(shù);
我們可以將過(guò)濾器理解為高級(jí)版的運(yùn)算符!
知識(shí)點(diǎn)有點(diǎn)多,再學(xué)下去是不是要吐了?
那我們今天就到此為止吧,下一篇,我們?cè)倮^續(xù)學(xué)習(xí)Jinja2的另外2個(gè)重要概念:
-
宏
-
模板繼承
看著就很有食欲啊,敬請(qǐng)期待!
如果本文對(duì)您有幫助,麻煩動(dòng)動(dòng)手指點(diǎn)點(diǎn)贊?
謝謝!