Python模板引擎Jinja2(一)

前言

來(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í)路徑

  1. 常見(jiàn)的Python模板引擎有哪些?
  2. Jinja2簡(jiǎn)介;
  3. Jinja2入門(mén)使用;
  4. 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文件,效果為:

瀏覽器打開(kāi)模板文件

沒(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);
項(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文件:

渲染html

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

瀏覽器訪問(wèn)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)容略有差異:

index為1時(shí)
index為2時(shí)
index為其他值時(shí)
(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后:
渲染新html
for語(yǔ)句渲染效果

這樣,我們順利將多條數(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ù);

details為空時(shí)
我們也可以遍歷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)置常量,有:

Jinja2中for循環(huán)內(nèi)置常量-來(lái)自網(wǎng)絡(luò)

篇幅有限,請(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)贊?

謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 模板: 在之前的章節(jié)中,視圖函數(shù)只是直接返回文本,而在實(shí)際生產(chǎn)環(huán)境中其實(shí)很少這樣用,因?yàn)閷?shí)際的頁(yè)面大多是帶有樣式和...
    帥氣的Lucky閱讀 1,965評(píng)論 0 1
  • ### Flask渲染Jinja2模板和傳參: 1. 如何渲染模板: * 模板放在`templates`文件夾下 ...
    水漾漣漪penny閱讀 5,270評(píng)論 0 1
  • 隨著程序內(nèi)容改變,視圖函數(shù)也有可能需要變化。模板是一個(gè)包含響應(yīng)文本的文件,其中包含用占位變量表示的動(dòng)態(tài)部分,其具體...
    容澄閱讀 2,746評(píng)論 0 0
  • 來(lái)嘞早不如來(lái)的巧,剛翻譯好,你就來(lái)啦!翻譯完成 要開(kāi)發(fā)CMS(內(nèi)容管理系統(tǒng))得有個(gè)模板引擎,Tera是使用Rust...
    不安分的程序員天朗閱讀 2,986評(píng)論 0 0
  • 視圖函數(shù)的主要作用是生成請(qǐng)求的響應(yīng),這是最簡(jiǎn)單的請(qǐng)求。實(shí)際上,視圖函數(shù)有兩個(gè)作用:處理業(yè)務(wù)邏輯和返回響應(yīng)內(nèi)容。在大...
    __method__閱讀 559評(píng)論 0 0

友情鏈接更多精彩內(nèi)容