Flask06——Jinja2模板引擎
为什么要用模板
到目前为止,我们的视图函数返回的一直是简单的字符串,而我们很清楚的知道,我们的flask框架是做web开发的,也就是要做出来漂亮的页面出来,可是我们现在仅仅只返回了几个字符串,好像跟我们所预想的网站相差甚远。我们要怎样做出我们所看到的各种绚丽多彩的网站呢?答案就是:可以通过模板实现。那么,模板是什么呢?作用为何?模板其实就是一个个的html页面,我们知道html页面最基本的作用就是用来展示,而我们的html页面用到我们的flask框架中,就可以配合实现从处理业务逻辑到返回响应的效果。
这里我们提到了两个功能:1、处理业务。2、返回响应。这两个功能也是我们视图函数的两个功能。而如果我们把这两个功能都写在视图函数内部的话,就会增加视图函数的复杂度及维护成本。那么模板就很好的解决了这样一个问题,将处理业务的代码和页面展示代码分开,降低了代码的耦合度。如果我们需要在展示页面放置变量的话,可以由视图函数将变量传递到模板中来使用。
模板的功能
提到模板这个功能,就不得不说一下Jinja2这个库,这个库就是专门做模板引擎的,也就是解决试图函数和模板调用,传值等一系列问题的。
模板内部放置的也是一个大的字符串,只是我们把这个大字符串单独放到了一个html页面,基于html语言的语法,将页面进行布局,划分页面结构,以备未来给css来设置样式,给js来设置交互效果。
而我们需要从试图函数中传递过来的变量,需要用双大括号{{ }}括起来,我们的Jinja2模板引擎就可以配合我们的框架将变量给解析出来。而解析变量的这个过程我们称之为渲染
。
另外,我们还可以在页面当中写业务逻辑 if else for循环登录,这些业务逻辑一般需要包在{% %}的符号中,才能在html页面当中被识别出来,背后还是Jinja2模板语言帮我们进行识别的。
如何调用模板和传递变量
我们的模板文件需要放到和入口文件start.py同级的名称叫做templates的文件夹中。flask提供了render_template函数来调用模板,第一个参数即为html页面的名称,后面可以放置多个我们需要传递到模板中的变量,然后在模板页面就可以通过{{变量名}}的方式进行调用了。另外模板也支持变量的计算,通过字典.下标
的形式取到字典某个下标对应的值等功能,都会在下面通过代码注释给大家标注出来。文件名称都会写到代码最上方。
# start.py文件
# 导入包
from flask import Flask, render_template
@app.route('/')
def index():
my_str = 'Hello World!'
my_int = 100
my_list = [1, 2, 3, 4, 5, 6]
my_dict = {'name': 'xiaoming', 'age': 16}
return render_template('index.html',
my_str = my_str,
my_int = my_int,
my_list = my_list,
my_dict = my_dict
) # 第一个参数即为模板文件名称,index.html文件放在和此start.py文件同级的templates文件夹下面,后面的参数即为传递到模板中的变量。
在模板index.html文件中就可以这样使用了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
{{ my_str }} <br>
{{ my_int }} <br>
{{ my_list }} <br>
{{ my_dict }} <br>
<hr>
{{ my_int + 10 }} <br> <!--变量和整型计算-->
{{ my_int + my_list[2] }} <br> <!--通过中括号形式访问列表元素且进行计算-->
{{ my_list.5 }} <br> <!--通过 列表.下标 方式取值-->
{{ my_dict['name'] }} <br> <!--通过中括号形式取值-->
{{ my_dict.age }} <!--通过 字典.下标 方式取值--->
</body>
</html>
运行请求首页视图函数,看看是不是正常打印了各个变量呢?
过滤器
对于我们传递到模板当中的变量,有时候可能需要做一些改变,或者是格式化,运算等等。对于此类需求,Jinja2也给我们提供了过滤器来解决。过滤器就相当于我们在Python中的函数,传递值到过滤器,就会按照过滤器的功能给我们返回相应的结果,使用形式是这样的{{ 变量 | 过滤器 }},我们可以看看下面在模板中怎么使用过滤器的。
{{ my_str | upper }} <br> <!--首字母大写-->
{{ my_str | lower }} <br> <!--全部字母转为小写-->
{{ my_list | first }} <br> <!--取列表第一个元素-->
{{ my_list | last }} <br> <!--取列表最后一个元素-->
{{ my_list | length }} <br> <!--计算列表长度-->
{{ my_list | sum }} <br> <!--计算列表元素总和-->
{{ my_list | sort }} <br> <!--对列表元素进行排序-->
{{ [6,2,3,1,5,4] | sort }} <br> <!--对列表元素进行排序-->
过滤器的功能已经在后面注释了,运行看看是否能达到应有的效果。
自定义过滤器
另外,我们还可以自定义过滤器,可以在flask入口文件当中进行定义。
# 此过滤器功能:过滤掉列表中大于3的元素
@app.template_filter('filter_large') # 自定义过滤器,参数为装装饰器的名称,也就是我们在模板中用的名字
def filter_large(my_list):
new_list = [] # 定义空列表
for i in range(len(my_list)): # 遍历传递过来的列表
if my_list[i] <= 3: # 判断每个元素的值是否小于等于3
new_list.append(my_list[i]) # 如果小于等于3则追加到新列表中
return new_list # 返回新列表
在模板中就可以这样来使用
{{ my_list | filter_large }}
运行看看效果。
模板中定义宏
宏其实也可以看成能够批量生成HTML标签的函数,定义和使用如下:
<!--在模板中定义宏格式:macro开头,宏名称(标签各属性)-->
{% macro input(label='', name='', type='text', value='') %}
<!--定义具体输出结果,将参数接收过来进行属性的赋值-->
<label>{{ label }}</label><input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}
<!--以endmacro结束-->
<!--宏的使用-->
<form action="">
<!--宏名称(传递值到宏中)-->
{{ input('用户名:', 'username') }}
{{ input('密码:', 'passwd', 'password') }}
{{ input(type='submit', value='注册') }}
</form>
模板的继承
我们在访问网站的时候一般都能感觉到网站的顶部和底部基本对于所有的页面都是固定不变的,那么在我们的模板当中对这种需求也有相应的解决方案。可以定义一个基础模板base.html,然后再定义一个首页index.html。让首页继承基础模板base.html,顶部和底部就使用基础模板的,只修改中间部分。代码如下
<!--base.html-->
<!--定义顶部代码块-->
{% block top %}
顶部
<hr>
{% endblock top %}
<!--定义中间代码块-->
{% block content%}
主内容区
{% endblock content %}
<!--定义底部代码块-->
{% block bottom %}
底部
<hr>
{% endblock bottom %}
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<!--继承基础目标-->
{% extends 'base.html' %}
<!--重写中间代码块-->
{% block content %}
首页
<hr>
{% endblock content %}
</body>
</html>
最后通过视图函数index调用index.html模板后,就能实现预期的效果。
包含
下面来演示一下模板的包含,也就是可以在一个模板当中把另外一个模板的内容包含进来
<!--index.html-->
<h1>首页</h1>
<!--将hello.html模板包含进来-->
{% include 'hello.html' ignore missing %} <!--ignore missing作用可以起到如果hello.html不存在的话不报错-->
<h3>底部</h3>
<!--hello.html-->
<h2>Hello</h2>
这样就可以把hello.html的内容包含到首页当中。
模板中访问内置函数和对象
在模板中还可以访问flask内置的函数和对象
# setting.py文件
DEBUG = True
TEST = 'test配置项'
SECRET_KEY = 'abc'
# start.py文件
from flask import Flask, render_template, session, g, request
app = Flask(__name__)
app.config.from_object('setting')
@app.route('/')
def index():
session['new'] = '新闻'
print(session['new'])
g.name = 'g变量name'
return render_template('index.html')
@app.route('/lists')
def lists():
return '文章列表页'
@app.route('/detail')
def detail():
id = request.args.get('id')
return '文章{}内容'.format(id)
if __name__ == '__main__':
app.run(port=8919)
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<h3>{{ config.TEST }}</h3> <!--模板中调用配置项-->
<h3>{{ request.url }}</h3> <!--模板中获取请求地址-->
<h3>{{ config.SECRET_KEY }}</h3> <!--模板中调用配置项-->
<h3>{{ session.new }}</h3> <!--模板中调用session值-->
<h3>{{ g.name }}</h3> <!--模板中调用g变量属性-->
<h3><a href="{{ url_for('lists') }}">文章列表页</a></h3> <!--模板使用url_for-->
<h3><a href="{{ url_for('detail', id=1) }}">文章详情页</a></h3> <!--模板使用带参数的url_for-->
</body>
</html>
flash闪现
当我们登录某个网站输入用户名,密码等信息后,如果有错误就会在网页上展示出来相应提示内容,flash闪现就是用来实现这个功能的。只要我们在视图函数中调用flash发送消息,flash的所有消息就会传递到模板中的get_flashed_messages()这个函数当中,我们对此函数进行遍历,就可以把所有flash消息展示出来。
# start.py
from flask import Flask, render_template, request, flash
app = Flask(__name__)
app.config.from_object('setting')
@app.route('/')
def index():
username = request.args.get('username')
passwd = request.args.get('passwd')
if username == 'xiaoming' and passwd == '111111':
flash('登录成功!')
else:
flash('用户名或密码错误!')
return render_template('index.html')
if __name__ == '__main__':
app.run(port=8761)
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for message in get_flashed_messages() %}
<h3>{{ message }}</h3>
{% endfor %}
</body>
</html>
启动服务验证一下是否能显示flash闪现消息。
下一篇: SSH 协议及其实现总结