Python jinja2 基礎知識
@
目錄jinja2原理
Flask 的render_template預設使用了jinja2的模板引擎渲染頁面
demo.py
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def demo(): return render_template('demo.html') if __name__ == '__main__': app.run(debug=True)
templates/demo.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>你好,</h1> </body> </html>
渲染出的html是這樣的
這和下面的程式碼的效果沒有什麼區別
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def demo(): html = """" <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>你好,</h1> </body> </html> """ return html if __name__ == '__main__': app.run(debug=True)
而且也能傳引數
demo.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def demo():
with open('templates/demo.html', 'r', encoding='utf-8') as file:
html = file.read()
html = html.replace('{{ your_name }}', 'pineapple')
return html
if __name__ == '__main__':
app.run(debug=True)
templates/demo.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>你好,{{ your_name }}</h1>
</body>
</html>
渲染結果如下所示:
這樣就簡單實現了前端html和後端python程式碼的互動,這就是jinja2和其他一些模板引擎的原理!
jinja2基本語法
-
{% ...%}
用於迴圈或判斷語句。 -
{{...}}
用於表示式的值的引用。 -
{# ...#}
用於模板引擎的註釋,如果註釋中存在模板引擎的語法,那麼使用將不被模板引擎認為是註釋,註釋中的語法將被執行。此時請使用{##}進行註釋。
普通傳值
語法:{{ python表示式 }}
templates/demo.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 400px;
height: 200px;
border: solid 2px red;
text-align: center;
padding: 20px;
line-height: 40px
}
</style>
</head>
<body>
<div>
<span>你的登入賬號為:{{ session.get('username') }}</span><br>
<span>這篇文章的標題:{{ article.title }}</span><br>
<span>文章的閱讀次數:{{ article.count + 1 }}</span><br>
</div>
</body>
</html>
demo.py
import os
from flask import Flask, render_template, session
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def demo():
session['username'] = 'Pineapple'
article = {
'title': 'Flask jinja2模板',
'count': 9999
}
return render_template('demo.html', session=session, article=article)
if __name__ == '__main__':
app.run(debug=True)
渲染結果:
jinja2的模板裡,字典可以用dict.key的方式獲取值
條件語句
語法
{% if %}
{% elif %}
{% else %}
{% endif %}
templates/demo.html繼續新增
{% if article.count % 2 == 0 %}
<span>{{ article.count }}可以被2整除,是個偶數</span>
{% else %}
<span>{{ article.count }}不可以可以被2整除,是個奇數</span>
{% endif %}
迴圈語句
語法
{% for %}
{% endfor %}
templates/demo.html繼續新增
{% for i in range(5) %}
<span>第{{ i }}次</span><br>
{% endfor %}
初始化變數
在jinja2模板中,用set
關鍵字初始化變數
{% set loop = 6 %}
{% for i in range(loop) %}
<span>第{{ i }}次</span><br>
{% endfor %}
過濾器
https://jinja.palletsprojects.com/en/2.11.x/templates/#id11
https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-filters
過濾器其實就是函式,以 | 分割,左邊的輸出作為右邊過濾器的引數輸入,有點類似於Linux的管道
內建過濾器
舉幾個栗子
safe
safe
(value)
將值標記為安全,這意味著在具有自動轉義啟用後,此變數將不會被轉義。
先看看不加safe
templates/demo.html 新增
{{ red_font }}
demo.py 新增
red_font = """
<span style="color: red">這是一段紅色的字</span>
"""
return render_template('demo.html', session=session, article=article, red_font=red_font)
可以看到它是以普通字串的形式展示在頁面上的
加上過濾器後
{{ red_font | safe }}
所以這個safe還是很有用地,之後向 Echarts js傳資料也會用到它
truncate
truncate
(s, length=255, killwords=False, end='...', leeway=None)
返回字串的截斷
副本。 長度已指定 第一個引數預設為 255
。 如果第二引數是 true
過濾器將剪下文字的長度。 除此以外 它將丟棄最後一個單詞。 如果文字是事實截斷後會附加省略號( "..."
)。 如果你想要一個 與 省略號不同的省略號 "..."
您可以使用的 第三個引數。 僅超出長度公差的字串 第四個引數中給出的空白將不被截斷。
{{ "foo bar baz qux"|truncate(9) }}
-> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
-> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
-> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
-> "foo bar..."
如果killwords=True,那麼返回的字串的長度為指定的長度 + end長度:length + len(end)
這個truncate還是挺複雜的,不明白老外為啥非得這麼搞,就不能像python裡的切片一樣嗎?
更詳細的解釋請看這位同志:https://blog.csdn.net/yueguangmanong/article/details/85196199
呼叫自定義函式
在模板中呼叫python中的函式,主要又兩種方法
裝飾器
使用上下文處理器context_processor
這種呼叫方式,準確的說不是呼叫函式,而是呼叫返回值的引數,且返回值必須是字典形式,也可以說是json格式
dem.py
@app.context_processor
def func():
result1 = {'1': 'Python', '2': 'Linux', '3': 'Java'}
result2 = [1, 2, 3, 4, 5, 6]
return dict(result1=result1, result2=result2)
templates/demo.html
{{ result1 }}
{{ result2 }}
{{ result1['1'] }}
渲染結果
這種方式如果想要傳參,得使用兩層閉包
demo.py
@app.context_processor
def func():
def func1(args1):
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result[args1]
return dict(func1=func1)
tmeplates/demo.html
{{ func1('1') }}
渲染結果
全域性註冊
在全域性jinja_env中註冊自定義函式
demo.py
def func():
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result
app.jinja_env.globals.update(func=func)
templates/demo.html
{{ func() }}
注意這時是要加小括號()的,不然得到的將是函式的地址,而不是呼叫函式
渲染結果
這種方式的話,傳引數會變得簡單些
def func(args):
result = {'1': 'Python', '2': 'Linux', '3': 'Java'}
return result[args]
app.jinja_env.globals.update(func=func)
{{ func('2') }}
渲染結果
呼叫自定義過濾器
過濾器其實就是一種特殊的函式,將|前的值作為|後的函式第一個引數,函式返回值為最終結果
也是有兩個方法,不過都大差不差
裝飾器
呼叫模板過濾器template_filter,引數為過濾器名,和函式名並無關係
demo.py
@app.template_filter('my_len')
def my_len(s):
return len(s)
templates/demo.html
{{ "Hello, how are you ? " | my_len }}
渲染結果
全域性註冊
與自定義函式一樣,同樣是註冊到jinja_env裡
def my_len(s):
return len(s)
app.jinja_env.filters.update(my_len=my_len)
渲染結果和上面一樣,不演示了。