文 / 秦未
1.jinja2解析
今天學習Flask的模板引擎 -- jinja2,我們先看看它工作的原理:
說明:視圖函數通過上下文與模板之間傳遞數據,模板由jinja2引擎驅動支持并生成HTML文件,這樣展示在客戶端瀏覽器中的內容就是完整的頁面了。
我們之前有一個范例:
@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內容 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關于頁面</title>
</head>
<body>
{{ text }}
</body>
</html>
運行輸出:
其中我們發現h1并沒有生效,而是作為字符串完整的顯示了出來,其實這是jinja2的自動轉義功能在起作用,主要目的是防止跨站腳本攻擊。
但如果我們能保證內容是安全的,我們想要實現標簽的作用該怎么辦呢?
jinja2提供兩種辦法禁用自動轉義功能。
1.塊元素包裹內容:
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關于頁面</title>
</head>
<body>
{% autoescape false%}
{{ text }}
{% endautoescape %}
</body>
</html>
說明:在{% autoescape false%}{% endautoescape %}內包裹的所有內容都會被禁止自動轉義。
2.單獨的
{#/app/templates/blog/about.html#}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>關于頁面</title>
</head>
<body>
{{ text|safe }}
</body>
</html>
說明:在指定值后面加 “|safe”,即可在這個值中禁用自動轉義。
最后效果是一樣的:
第二種方法其實是模板引擎的過濾器,本質來說這是一種值的預處理方法(函數),每一個過濾器代表一個方法(函數),它接收|之前的參數,然后輸出內容在當前位置,在模板中一個變量可同時使用多個過濾器,解析從左往右。
jinja2本身提供了相當多的過濾器,正常情況下足夠我們使用了,當然我們也可以自定義過濾器。
2.自定義過濾器示例:
我們需要一個markdown過濾器,官方并沒有提供。
首先下載一個mistune模塊,這個markdown解析庫是Python中最快的,據稱比Markdown模塊快10倍左右。
pip install mistune
然后在app.py 內增加一個裝飾器加函數:
# /app/app.py
@app.template_filter('md')
def markdown_to_html(text):
import mistune
markdown = mistune.Markdown()
return markdown(text)
同時為了驗證,修改about函數:
# /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>關于頁面</title>
</head>
<body>
{{ text|safe }}
{{ body|md|safe }}
</body>
</html>
運行效果:
有時候,我們想在前臺運行一個函數怎么辦?
比如我們想實現一個功能:定義一個函數讀取目錄下的md文件并輸出到前臺。
先看源碼:
# /app/app.py
def read_md(filename):
from functools import reduce
# 獲取當前路徑
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函數傳遞到前臺
@app.context_processor
def inject_methods():
return dict(read_md=read_md)
先建立一個在app目錄下的名叫md.md的文件:

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