目录
第三章 jinja2模板引擎
在Flask中常用jinja2模板引擎实现复杂的页面渲染,jinja2是灵活,快速和安全的模板引擎技术。
本章主要涉及的知识点有:
-
如何使用Flask渲染模板;
-
在模板中引用一个或多个参数
-
if语句在模板中的使用
-
for语句在模板中的使用
3.1模板引擎概述及简单实用
思考:随着不同终端的兴起,开发人员如何写一份功能代码在所有设备上都能使用
高度重视前后端的分离,后段负责业务逻辑/数据访问,前端负责展现/交互逻辑
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/user/<username>')
def user(username):
return render_template('user.html')
if __name__ == '__main__':
app.run()
我的理解就是把网页(html文件)挂在了服务器上
Flask通过render_template()函数来实现模板的渲染,使用jinja2模板引擎,需要from flask import render_template命令导入render_template函数。在视图函数中使用return方法,render_template()函数的首个函数声明使用哪个模板文件。
3.2向模板中传递参数
-
单个变量
在app.py文件上把username=name
@app.route('/user/<username>') def user(username): return render_template('user.html', name=username)
在html文件中带入参数,用{{}}
<h1>欢迎您:{{name}} </h1>
-
多个变量
在app.py文件中
def index(): title ='python的键值对' author = 'jack' return render_template('index.html',**locals()) 或return render_template('index.html',var1=title,var2=title2)
在在html文件中
</head> <body> 传过来的标题:{{title}} 或传过来的标题:{{var1}} <br> 传过来的作者:{{author}} 或传过来的作者:{{var2}} </body>
总结:在render_template()函数中,如果给模板传递全部本地变量,可以使用**locals()方法,
此时,在模板中可以使用{{title}} 和 {{author}}来直接表述变量。
3.3模板中控制语句之if语句
在app.py文件中
import random#导入random模块 app = Flask(__name__)#Flask初始化 @app.route('/') #定义路由 def hello_world():#定义视图函数 rand1=random.randint(0,1)# 产生0-1范围内的整型数 return render_template('index.html',name=rand1)#渲染模板,并向模板传递值
在html文件中
</head> <body> {% if name %}<!-- name值是否存在--> <h1>产生的随机数有效! </h1><!-- name值存在,则输出产生的随机数有效!--> {% else %}<!-- name值不存在--> <h1>产生的随机数无效! </h1><!-- name值不存在,则输出产生的随机数无效!--> {% endif %}<!-- 结束if--> </body>
在此例子中random随机函数0无效,1有效,所以刷新页面有不同的效果。
由此,可以制作一个抽奖的随机系统(html文件)
建议:多使用if——elif——elif——else——endif 结构
</head> <body> {% if name==0 %} <h1>重在参与</h1> {% elif name==1 %} <h1>恭喜,您抽得了一等奖</h1> {% elif name==2 %} <h1>恭喜,抽得了二等奖!</h1> {% else %} <h1>恭喜,抽得了三等奖!</h1> {% endif %} {{ name }} <!--显示随机数--> </body>
总结:模板表达式都是在分隔符 {{}} 内的;
控制语句都是在 {% %} 内的;(注意紧密想连)
模板注释放在 {# #} 内。
3.3模板中控制语句之for语句
app.py文件
def hello_world():#定义视图函数 goods = [{'name': '怪味少女开衫外套春秋韩版学生bf原宿宽松运动风2018新款秋装上衣', 'price': 138.00}, {'name': 'A7seven 复古百搭牛仔外套女秋季2018新款宽松显瘦休闲夹克衫上衣', 'price': 100.00}, {'name': '黑色时尚西装外套女春秋中长款2018新款韩版休闲薄款chic西服上衣', 'price': 100.00}, {'name': 'HAVE RICE饭馆 颜值超耐打 复古牛仔外套女短款 2018春秋新款上衣', 'price': 129.00} ]#定义列表goods return render_template('shop.html', **locals())#渲染模板,并向模板传递参数
html文件(建表操作)
注意:正确写法{% for goods in goods %},不能{ %% },{和%必须紧密相连。
<table> <thead> <th>商品名称</th> <th>商品价格</th> </thead> <tbody> <meta charset="UTF-8"> {% for goods in goods %} <tr> <td>{{goods.name}} <td>{{goods.price}} </tr> {% endfor %} </tbody> </table>
在hello_world视图函数中定义一列表goods,期属性主要是name和price,用for语句将其遍历出来。
总结:在模板中,使用if和for语句更好渲染模板,通过{%逻辑表达语句%}可以实现代码的嵌套,
与Python基本一致,但必须要在{%%}内部。
3.5 Flask的过滤器
过滤器本质就是一个转换函数,有时候我们不仅需要输出变量的值,还需要把某个变量的值修改在显现出来,
而在模板中不能直接调用Python中的某些方法,这莫就利用到了过滤器。
3.5.1常见过滤器(没运行出来)
列如:P42
app.py文件
#encoding:utf-8 from flask import Flask,render_template#导入Flask以及render_template模块 app = Flask(__name__)#Flask初始化 @app.route('/')#定义路由 def hello_world():#定义视图函数 student={ 'name':'wangjie', 'age':-18 } return render_template('index.html',**student)#渲染模板,并向模板传递值 if __name__ == '__main__': app.run()
html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"><!--设置网页编码--> <title>过滤器</title><!--设置网页标题--> </head> <body> <p>{{ age|abs }}</p><!--对age进行绝对值运算--> <p>{{'hello'|capitalize}}</p><!--将字符串hello转化成Hello,实现首字母大些--> <p>{{'hello'|replace('h','x')}}</p><!--将hello中的字母h替换成x--> <p>{{[01,80,42,44,77]|first}}</p><!--取得列表中的首个元素--> <p>{{[01,80,42,44,77]|last}}</p><!--取得列表中的最后一个元素--> <p>{{[01,80,42,44,77]|count}}</p><!--取得列表中的元素中个数--> <p>{{[01,80,42,44,77]|sort}}</p><!--列表中的元素重新排序,默认按照升序进行排序 --> <p>{{[01,80,42,44,77]|join(',')}}</p><!--将列表中的元素合并为字符串 --> <p>{{18.8888|round(2,'floor')}}</p><!--保留小数点后2位,返回结果为18.88--> <p>{{18.8888|round}}</p><!--四舍五入取得整数 --> <p>{{-2|abs}}</p><!--进行绝对值运算 --> </body> </html>
3.5.2自定义过滤器(含不理解部分)
通过add_template_filter方法实现自定义过滤器,
第一个参数是函数名,第二个函数名自定义的过滤器名称。
app.py ——实现每三行输出一条分割线
#encoding:utf-8 import sys#导入sys模块 from flask import Flask,render_template#导入Flask和render_template模块 app = Flask(__name__)#Flask初始化 @app.route('/')#定义路由 #视图函数 def hello_world(): goods = [{'name': '怪味少女开衫外套春秋韩版学生bf原宿宽松运动风2018新款秋装上衣'}, {'name': 'A7seven 复古百搭牛仔外套女秋季2018新款宽松显瘦休闲夹克衫上衣'}, {'name': '黑色时尚西装外套女春秋中长款2018新款韩版休闲薄款chic西服上衣'}, {'name': 'HAVE RICE饭馆 颜值超耐打 复古牛仔外套女短款 2018春秋新款上衣'}, {'name': ' 颜值超耐打 复古牛仔外套女短款 2018春秋新款上衣'}, {'name': 'HAVE RICE饭馆 复古牛仔外套女短款 2018春秋新款上衣'}, {'name': 'HAVE RICE饭馆 颜值超耐打 2018春秋新款上衣'}, {'name': 'HAVE RICE饭馆 颜值超耐打 复古牛仔外套女短款 '}, {'name': 'HAVE RICE饭馆 颜值超耐打 复古牛仔外套女短款 2018春秋新款上衣end'}, ]#定义列表goods return render_template('index.html',**locals())#渲染模板,并向模板传递值 def do_index_class(index):#定义函数 if index % 3==0:#每间隔3行输出line return 'line' else: return '' <!--不李姐部分--> app.add_template_filter(do_index_class,'index_class')#使用自定义过滤器添加css if __name__ == '__main__': app.run()
html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"><!--设定网页编码--> <title>Title</title><!--设定网页标题--> <style> .line{ display: inline-block; height:1px; width:100%; background:#00CCFF; overflow:hidden; vertical-align: middle; } </style> </head> <body> <meta charset="UTF-8"> {% for goods in goods %}<!--对列表进行遍历--> <!--不李姐部分--> <li style="list-style-type:none">{{ goods.name }} <span class="{{ loop.index | index_class }}"> </span></li><!--每3条记录输出一条分割线--> {% endfor %}<!--for循环完毕--> </body> </html>
3.6宏的定义及使用
3.6.1宏的定义
jinja2中的宏功能有些类似于传统编程语言中的函数,它跟Python中函数类似,可以传递参数,
但不能有返回值,可以将一些经常用的代码放入宏中,然后把一些不固定的值取出来作为一个变量。
定义宏
{% macro input(name,type='text',value='')-%) <input type="{{type}}" name="{{name}}" value="{{value|e}}"> {{%-endmacro%}}
定义宏要加macro,定义宏结束要加endmacro标志。宏的名称就是input,
他有三个参数,分别是name,type和value,后两个参数有默认值。
我们可以使用表达式来调用这个宏:
<!--调用宏--> {{input('username')}} {{input('password',type='password')}}
登录系统:html文件如下,app.py文件就是把html文件运用jinja模板render_template()
{#宏的定义 #} {% macro input(name, type='text', value= '',size='40',placeholder="请在这里输入") -%} <input type="{{ type }}" name="{{ name }}" value="{{ value }}" size="{{ size }}" placeholder="placeholder"> {%- endmacro %} {#宏的使用#} <div style="color:red"> <p> 用户名 :{{ input('username')}}</p> <p> 密 码 :{{ input('password',type='password')}}</p> <p> 登 录 :{{ input('submit',type='submit',value='登录')}}</p> </div>
3.6.2宏的导入
建立一个专门放宏的文件from.html
{% macro input(name, type='text', value= '' ,size=20, placeholder="请在这里输入用户名") -%} <input type="{{ type }}" name="{{ name }}" value="{{ value }}" size="{{ size }}", placeholder="{{ placeholder }}"> {%- endmacro %}
html文件,app.py文件不再赘述
{% from 'form.html' import input %} <!--导入宏--> <div style="color:red"> <p> 用户名 :{{ input('username')}}</p> <p> 密 码 :{{ input('password',type='password')}}</p> <p> 登 录 :{{ input('submit',type='submit',value='登录')}}</p> </div>
3.6.3 include的使用
宏文件中引用其他宏,可以使用include语句。include语句可以把一个模板引入到另一个模板中。
index.html-------主html文件
<style type="text/css"> .header{ width: 100%; height:40px; margin:20px 20px; } .footer{ width: 100%; height: 40px; margin:20px 20px; } .content{ width: 100%; height: 40px; margin:20px 20px; } </style> </head> <body> {% include "header.html" %} <div class="content"> 这是网页内容 </div> {% include "footer.html" %} </body>
header.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <div class="header"> 这是网页头部 </div> </body> </html>
3.7 set和with语句的使用
set与with语句都可以在jinja2中定义使用并赋予值。set定义的变量在整个模板范围内都有效。
with关键字在定义变量和与赋值同时,限制了with定义变量的作用范围。
-
set用法
-
给变量赋值
{% set telephone ='1388888888' %}
-
给列表与数组赋值
{% set nav = [('index.html', 'index'), ('product.html', 'product')] %}
在模板中使用{{telephone}}和{{nav}}来引用这些定义变量。
-
with用法
{% with pass = 60 %} {{ pass }} {% endwith %}
with定义变量的作用范围在{% with %}和{% endwith %}代码内,在模板的其他地方,引用此变量无效。
3.8 静态文件加载(引用多种文件)
静态文件的加载一般需要先新建文件夹static,在文件夹下在建立css、js和images文件夹,
在这里存放css、js、images,同时需要使用"url_for"函数
在template目录下新建一个名为index.html文件,在app.py的视图函数中使用
return render_template('index.html')方法来渲染模板。
<head> <meta charset="UTF-8"> <title>Title</title> <!--加载js文件 两种方法--> {#<script src="{{ url_for('static', filename='js/jquery-3.3.1/jquery-3.3.1.js') }}"></script>#} <script type="text/javascript" src="static/js/jquery-3.3.1/jquery-3.3.1.js"></script> <!--加载外部css文件--> <link rel="stylesheet" href="{{ url_for('static',filename='css/car.css') }}"> </head> <body> <!--测试js文件是否加载成功--> {#测试jquery是否加载#} <script> if(jQuery) { alert('jQuery已加载!'); } else { alert('jQuery未加载!'); } </script> <div class="img"> <!--加载外部图片文件--> <img src="{{ url_for('static', filename='images/car.jpg') }}"></img> </div> </body>
3.9模板的继承
在templates目录中创建index.html、base.html和product.html 3个静态文件。
base.html文件作为基类,index.html和product.html文件作为子类,子类去继承基类的基本内容。
base.html
<html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %} -我的网站</title> </head> <body> {% block body %} 这是基类中的内容 {% endblock %} </body> </html>
index.html
{% extends "base.html" %} {% block title %}网站首页{% endblock %} {% block body %} <!--子模板仍要保持父模板中的代码--> {{ super() }} <h4>这是网站首页的内容!</h4> {% endblock %}
product.html
{% extends "base.html" %} {% block title %}产品列表页{% endblock %} {% block body %} <h4>这是产品列表页的内容!</h4> <!--在一个block中调用其他block中的代码,用{{ self.其他block的名称() }}--> <h4> 取得网页标题的内容: {{ self.title() }}</h4> {% endblock %}
3.10 练习
1.使用for语句,新建一个工程,打印出九九乘法表。
app.py
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): for i in range(1, 10): for j in range(1, i + 1): print(str(j) + str("*") + str(i) + "=" + str(i * j), end="\t") print() return 'Hello World!' if __name__ == '__main__': app.run()
2.在视图函数中定义一个字典books,请在模板中遍历出字典的所有属性。
app.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def hello_world(): books = [ { 'name': '红楼梦', 'author': '曹雪芹', 'price': 200 }, { 'name': '水浒传', 'author': '施耐庵', 'price': 100 } ] return render_template('index.html',**locals()) if __name__ == '__main__': app.run()
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"><!-- 设定网页编码--> <title>Title</title><!-- 设定网页标题--> </head> <body> <table><!-- 定义表格--> <thead> <th>书名</th> <th>作者</th> <th>价格</th> </thead> <tbody> <meta charset="UTF-8"> {% for books in books %}<!-- for循环开始--> <tr> <td>{{ books.name}}</td><!-- 显示商品名--> <td>{{ books.author}}</td><!-- 显示价格--> <td>{{ books.price}}</td><!-- 显示价格--> </tr> {% endfor %}<!-- for循环结束--> </tbody> </table> </body> </html>