Flask中Jinja2模板使用总结

之前已经总结过Jinja2了,这里主要总结在Falsk中的一些东西。包括以下方面

  • 模板的目录结构设计
  • 常用的模块
  • HTML转义
  • 特殊装饰器

模板的目录设计

没有绝对答案,从别人博客复制一个结构又加了一点补充,更详尽的可以参考他的博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| - projectName
| - app //程序包
| - templates //jinjia2模板
| - layout.html
| - index.html
| - about.html
| - profile/
| - layout.html
| - index.html
| - photos.html
|- admin/
| - layout.html
| - index.html
| - analytics.html
|- static //css,js 图片等静态文件
| - main //py程序包 ,可以有多个这种包,每个对应不同的功能
| - __init__.py
|- errors.py
|- forms.py
|- views.py
|- __init__.py
|- email.py //邮件处理程序
|- models.py //数据库模型
|- migrations //数据迁移文件夹
| - tests //单元测试
|- __init__.py
|- test*.py //单元测试程序,可以包含多个对应不同的功能点测试
|- venv //虚拟环境
|- requirements.txt //列出了所有依赖包以及版本号,方便在其他位置生成相同的虚拟环境以及依赖
|- config.py //全局配置文件,配置全局变量

常用的模块

1
2
3
4
5
6
7
8
9
from flask import Flask,render_template
@app.route('/about')
def about():
return render_template('about.html',user='Gourds')
"""
render_template参数说明:
第一个参数是模板名称,默认会在当前路径下的templates中查找
user='Gourds',其中左边data1表示模板中的占位符,右边表示在当前视图中的变量
"""

如下就是HTML的例子(定义user返回hello不然返回gun)。变量表达式使用{{ }},控制语句使用{% %}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Gourds</title>
</head>
<body>
&#123;% if user is defined() %&#125;
<h1> Hello &#123;&#123; user &#125;&#125; !</h1>
&#123;% else %&#125;
<h1> Gun !</h1>
&#123;% endif %&#125;
</body>
</html>

HTML自动转义

jinja2默认情况下实惠自动转义的。如下,会被自动转义

1
2
3
@app.route('/index')
def index():
return '<h1> Welcome %s </h1>' % '<em>Gourds<em>'

不过有时候你可能就是想让输出这个,在Flask中可以使用Marup实现

1
2
3
4
from flask import Markup
@app.route('/index')
def index():
return Markup('<h1> Welcome %s </h1>') % '<em>Gourds<em>'

自动转义的原因
原因:被渲染到页面的对象中没有实现__html__方法的对象。换句话说,就是假设一个对象实现了__html__方法那么这个对象就是安全的,jinja2模板就不会将它转义,即使他就是个恶意的脚本,那么为了防止被恶意脚本攻击,jinja2模板默认开启了自动转义,频繁的自动转义是会大量的消耗资源的,所以在确定该数据是安全的情况下可以用过滤器|safe或者&#123;% autoescape false %&#125;&#123;% endautoescape %&#125;关闭转义环境

  • safe过滤器:
    过滤器safe在源码中是将对象转换成一个Mark_up类的对象并实现了__html__方法,所以数据对象就被标记为安全然后渲染到前端
  • autoescape:
    将对象处于一个没有转义的环境下直接渲染到前端,跟__html__没有关系

模板继承&include&宏

之前在jinja语法中写过了,在这就简单记下

模板继承

1
2
3
4
5
&#123;&#123; extends "layout.html" &#125;&#125;
&#123;&#123; block content &#125;&#125;
&#123;&#123; var1 &#125;&#125;
&#123;&#123; fun(a,b)&#125;&#125;
&#123;&#123; endblock &#125;&#125;

include模板

包含的模板会被传递到当前的上下文,使用import的话就不会。导入不会像包含被缓存,因为导入经常只作为容纳宏的模块

1
&#123;% include 'header.html' without context %&#125;

宏其实就类似程序中的function,用来替代重复性操作

1
2
3
4
5
6
7
8
<!-- 定义 -->
&#123;% macro input(name, value='', type='text', size=20) -%&#125;
<input type="&#123;&#123; type &#125;&#125;" name="&#123;&#123; name &#125;&#125;" value="&#123;&#123;
value|e &#125;&#125;" size="&#123;&#123; size &#125;&#125;">
&#123;%- endmacro %&#125;
<!-- 使用 -->
<p>&#123;&#123; input('username') &#125;&#125;</p>
<p>&#123;&#123; input('password', type='password') &#125;&#125;</p>

两个特殊装饰器

@app.template_globle

这个装饰器可以使所有的模板都可以直接调用被装饰的函数

1
2
3
@app.template_global()
def hi(x, y):
return str(x) + str(y)
1
<h1>&#123;&#123; hi('hello', 'world')&#125;&#125;</h1>

@app.template_filter

这个装饰器下的函数可以方便测试表达式,比如IF判断&#123;&#123; if a|fun(b,c) &#125;&#125;

1
2
3
@app.template_filter()
def hello(a, b, c):
return a - b - c
1
<h2>&#123;&#123; 1|hello(2, 3) &#125;&#125;</h2>