
文 / 秦未
1.jinja2解析
今天學(xué)習(xí)Flask的模板引擎 -- jinja2,我們先看看它工作的原理:

說明:視圖函數(shù)通過上下文與模板之間傳遞數(shù)據(jù),模板由jinja2引擎驅(qū)動支持并生成HTML文件,這樣展示在客戶端瀏覽器中的內(nèi)容就是完整的頁面了。
我們之前有一個范例:
@app.route('/about')
def about():
return '<h1>about</h1>'
我們改變一下:
@app.route('/about')
def about():
return render_template('blog/about.html', **{
'text': 'Hello, World',
})
其中about.html內(nèi)容 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關(guān)于頁面</title>
</head>
<body>
{{ text }}
</body>
</html>
運行輸出:

其中我們發(fā)現(xiàn)h1并沒有生效,而是作為字符串完整的顯示了出來,其實這是jinja2的自動轉(zhuǎn)義功能在起作用,主要目的是防止跨站腳本攻擊。
但如果我們能保證內(nèi)容是安全的,我們想要實現(xiàn)標簽的作用該怎么辦呢?
jinja2提供兩種辦法禁用自動轉(zhuǎn)義功能。
1.塊元素包裹內(nèi)容:
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關(guān)于頁面</title>
</head>
<body>
{% autoescape false%}
{{ text }}
{% endautoescape %}
</body>
</html>
說明:在{% autoescape false%}{% endautoescape %}內(nèi)包裹的所有內(nèi)容都會被禁止自動轉(zhuǎn)義。
2.單獨的
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關(guān)于頁面</title>
</head>
<body>
{{ text|safe }}
</body>
</html>
說明:在指定值后面加 “|safe”,即可在這個值中禁用自動轉(zhuǎn)義。
最后效果是一樣的:

第二種方法其實是模板引擎的過濾器,本質(zhì)來說這是一種值的預(yù)處理方法(函數(shù)),每一個過濾器代表一個方法(函數(shù)),它接收|之前的參數(shù),然后輸出內(nèi)容在當(dāng)前位置,在模板中一個變量可同時使用多個過濾器,解析從左往右。
jinja2本身提供了相當(dāng)多的過濾器,正常情況下足夠我們使用了,當(dāng)然我們也可以自定義過濾器。
2.自定義過濾器示例:
我們需要一個markdown過濾器,官方并沒有提供。
首先下載一個mistune模塊,這個markdown解析庫是Python中最快的,據(jù)稱比Markdown模塊快10倍左右。
pip install mistune
然后在app.py 內(nèi)增加一個裝飾器加函數(shù):
# /app/app.py
@app.template_filter('md')
def markdown_to_html(text):
import mistune
markdown = mistune.Markdown()
return markdown(text)
同時為了驗證,修改about函數(shù):
# /app/app.py
@app.route('/about')
def about():
return render_template('blog/about.html', **{
'text': '<h1>Hello, World</h1>',
'body': '## 演示'
})
about.html也要修改:
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關(guān)于頁面</title>
</head>
<body>
{{ text|safe }}
{{ body|md|safe }}
</body>
</html>
運行效果:

有時候,我們想在前臺運行一個函數(shù)怎么辦?
比如我們想實現(xiàn)一個功能:定義一個函數(shù)讀取目錄下的md文件并輸出到前臺。
先看源碼:
# /app/app.py
def read_md(filename):
from functools import reduce
# 獲取當(dāng)前路徑
basepath = path.abspath(path.dirname(__file__))
# 將路徑連接
upload_path = path.join(basepath, filename)
with open(upload_path, encoding='UTF-8') as md_file:
# reduce為歸納的意思,主要作用是讓獲取的每一行都加上前一行。
content = reduce(lambda x, y: x + y, md_file.readlines())
return content
# 將read_md函數(shù)傳遞到前臺
@app.context_processor
def inject_methods():
return dict(read_md=read_md)
先建立一個在app目錄下的名叫md.md的文件:

## 1.jinja2解析
今天學(xué)習(xí)Flask的模板引擎 -- jinja2,我們先看看它工作的原理:
使用:
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關(guān)于頁面</title>
</head>
<body>
{{ text|safe }}
{{ body|md|safe }}
{{ read_md('md.md')|md|safe }}
</body>
</html>
{{ read_md('md.md')|md|safe }}這段代碼從左往右執(zhí)行,先執(zhí)行這個函數(shù)read_md('md.md'),再將獲取的內(nèi)容轉(zhuǎn)換為HTML,同時這個內(nèi)容不需要轉(zhuǎn)義。
運行效果:

---end---