做为python web开发领域的一员,flask跟Django在很多地方用法以都是相似的,比如flask的模板
模板就是服务器端的页面,在模板中可以使用服务端的语法进行输出控制
1.模板的工作原理
在视图函数中,通过render_template
方法返回一个页面,然后通过Jinja2语法来进行渲染
简单来说,就是把服务器端的html页面解释成用户看到的页面,而视图函数是通过上下文对象来进行变量的传递
在项目开发中,视图函数经常会把一些服务器处理完成的变量传递给前端页面进行渲染,
比如在下面的例子中,由render_template
返回html页面时,携带一些变量数据给Jinja2语法进行渲染
from flask import Flask, render_template
app = Flask(__name__)
app.debug = True
@app.route(\'/\')
def hello_world():
return \'Hello World!\'
@app.route(\'/detail\')
def detail():
message = {
\'name\':\'jack\',
\'text\':\'杰克\'
}
return render_template(\'detail.html\',info=message)
if __name__ == \'__main__\':
app.run(debug=True)
前端页面detail.html内容为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ info.name }}详细信息</h1>
<div>
我的名字叫:{{ info.text }}
</div>
</body>
</html>
启动项目,浏览器打开http://127.0.0.1:5000/detail
页面,前端页面渲染后效果为:
那么此时,如果后台返回给前端的变量为一段html代码,返回给前端经过Jinja2语法渲染后,效果会是怎么样的呢??
2.Jinja2语法安全机制
修改message变量,然后由render_template返回
@app.route(\'/detail\')
def detail():
message = {
\'name\':\'jack\',
\'text\':\'<h2>杰克</h2>\'
}
return render_template(\'detail.html\',info=message)
前端页面不变,刷新浏览器,效果如下
可以看到,返回的变量中包含html代码,但是Jinja2语法并没有对这一小段代码进行渲染,而是直接显示了出来
实际上这是为了安全,因为如果后台返回的html代码中包含恶意的js代码,如果直接就渲染了,会造成站点被攻击。
那如果我就是想渲染后台返回给前端的HTML代码,那应该怎么办呢
在flask中,如果确认后台返回给前端进行渲染的变量中包含的HTML代码是安全的,则可以使用一些方法来对这段HTML代码也进行渲染
方法一:autoescape 关闭安全机制
这种方法与Django的模板语法相同
后台代码不变,修改前端detail.html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% autoescape false %}
<h1>{{ info.name }}详细信息</h1>
<div>
我的名字叫:{{ info.text }}
</div>
{% endautoescape %}
</body>
</html>
此时,再次刷新页面,查看效果
方法二,调用Jinja2的safe过滤器
如果觉得第一种方法有点麻烦,可以使用第二种方法
后台代码不变,同样修改detail.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ info.name }}详细信息</h1>
<div>
我的名字叫:{{ info.text | safe }}
</div>
</body>
</html>
此时,再次刷新页面,效果跟第一种方法一样
在flask中,Jinja2语法提供了很多过滤器,可以在下面的地址进行查找
http://jinja.pocoo.org/docs/dev/templates/
3.自定义过滤器
在写文章或博客的时候,很多时候都会用到Markdown语法
在flask的Jinja2语法中,并没有标准的Markdown语法过滤器,此时可以使用扩展来自定义Markdown语法过滤器
修改flask项目文件
from flask import Flask, render_template
app = Flask(__name__)
app.debug = True
@app.route(\'/\')
def hello_world():
return \'Hello World!\'
@app.route(\'/detail\')
def detail():
message = {
\'name\':\'jack\',
\'text\':\'<h2>杰克</h2>\'
}
return render_template(\'detail.html\',info=message,markdown=\'## Markdown编辑器<br>`注释`\')
@app.template_filter(\'md\')
def markdown_html(txt):
from markdown import markdown
return markdown(txt)
if __name__ == \'__main__\':
app.run(debug=True)
修改detail.html前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ info.name }}详细信息</h1>
<div>
我的名字叫:{{ info.text | safe }}
{{ markdown | md | safe }}
</div>
</body>
</html>
刷新浏览器,查看效果
在实际开发中,后台向模板中传递的不只有变量和filter,还可能会向前端传递一个方法
,此时可以使用flask的上下文来实现
修改flask项目文件
#-*- coding: utf-8 -*-
from flask import Flask, render_template
app = Flask(__name__)
app.debug = True
@app.route(\'/\')
def hello_world():
return \'Hello World!\'
def read_md(filename):
from functools import reduce
with open(filename,encoding=\'utf-8\') as md_file:
content = reduce(lambda x,y:x + y, md_file.readlines())
return content
@app.context_processor
def methods():
return dict(read_md=read_md)
@app.route(\'/detail\')
def detail():
message = {
\'name\':\'jack\',
\'text\':\'<h2>杰克</h2>\'
}
return render_template(\'detail.html\',info=message,markdown=\'## Markdown\')
@app.template_filter(\'md\')
def markdown_html(txt):
from markdown import markdown
return markdown(txt)
if __name__ == \'__main__\':
app.run(debug=True)
如果想在Jinja2语法中调用后台定义的某个函数时,比如在这个例子中,前端页面中调用后台定义的read_md方法来处理某个Markdown格式的文件时,可以使用context_processor上下文处理器
。
在项目中应用了context_processor时,flask会把context_processor装饰的方法注册到Jinja2模板语法中
来,这样就可以在Jinja2语法中调用后台的方法了
用context_processor装饰的后台方法可以在前端所有的Jinja2语法中调用
修改前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ info.name }}详细信息</h1>
<div>
我的名字叫:{{ info.text | safe }}
{{ markdown | md | safe }}
{{ read_md(\'editor.md\') |md| safe}}
</div>
</body>
</html>
刷新浏览器,查看效果
使用过滤器和context_processor配置一起使用时,可以很灵活的进行页面的渲染