模板引擎
说明:
模板文件就是按照特定规则书写的一个负责展示效果的HTML文件 模板引擎就是提特定规则的解释和替换的工具
Jinja2
flask的模板引擎使用的就是Jinja2的模板引擎 它是由flask核心开发组成员开发的
一、模板的使用
(1) 准备工作 目录结构
project/
manage.py 项目启动控制文件
templates/ 模板文件的目录
(2) 渲染模板文件
在templates模板目录下 创建一个模板文件 hello.html 内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>Lucky老师 你好帅啊 好骚气啊</h4>
</body>
</html>
(3) 创建hello视图函数 代码如下
# 创建hello的路由地址
@app.route('/hello/')
def hello():
return 'hello'
(4) 渲染模板的方法
导入:
from flask import Flask,render_template,render_template_string
-
渲染模板
render_template(模板名称,**context)
-
返回一段渲染的html代码
render_template_string(渲染的HTML代码,**context)
使用实例:
# 创建hello的路由地址
@app.route('/hello/')
def hello():
# 渲染模板文件 hello.html
# return render_template('hello.html')
return render_template_string('<p style="font-size:20px;color:yellow;">lucky老师你好帅 我想和你生猴子</p>')
(5) 使用变量
简介:
-
视图传递给模板的数据
-
遵循标识符的命名规则
-
语法格式
{{ var }}
-
如果模板使用的变量不存在 则插入的为空白字符
实例:
manage.py
@app.route('/hello/')
def hello():
return render_template('hello.html',name='lucky',age=18,sex='男',hobby='写代码和学习')
hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h4>我叫:{{ name }} 我今年{{ age }}岁了 我的性别是{{ sex }} 我的爱好是{{ hobby }} 希望台上的女嘉宾你可以给我留灯</h4>
</body>
</html>
二、标签
格式:
{% tag %}
作用:
- 在输出中创建文本
- 控制逻辑和循环
(1) 流程控制 之 if
主体结构:
{% if ... %}
...
{% elif ... %}
...
{% else %}
...
{% endif %}
实例:
{% if grade >= 90 %}
成绩为{{ grade }} 优秀
{% elif grade >= 80 %}
成绩为{{ grade }} 良
{% elif grade >= 60 %}
成绩为{{ grade }} 合格
{% else %}
成绩为{{ grade }} 不合格
{% endif %}
(2) 流程控制之 for
主题结构:
{% for item in Iterable %}
...
{% else %}
...
{% endfor %}
实例:
<h4>for循环的使用</h4>
<ul>
{% for i in myRange %}
<li>{{ i }}</li>
{% else %}
<p>该变量不存在</p>
{% endfor %}
</ul>
迭代字典
<h4>迭代字典</h4>
{% for key,value in infoDict.items() %}
<p>key---->{{ key }} value----->{{ value }}</p>
{% endfor %}
在for循环中还包含一下变量 用来获取当前的遍历状态
变量 | 描述 |
---|---|
loop.index | 当前迭代的索引 从1开始 |
loop.index0 | 当前迭代的索引 从0开始 |
loop.first | 是否为第一次迭代 返回True/False |
loop.last | 是否为最后一次迭代 返回True/False |
loop.length | 迭代的长度 |
实例:
<h4>获取迭代时的状态</h4>
<ul>
{% for i in myRange %}
<li>{{ loop.index }}----{{ loop.index0 }}-----{{ loop.first }}-----{{ loop.last }}-------{{ loop.length }}</li>
{% endfor %}
</ul>
注意:
- for循环搭配的else 只有当迭代的变量不存在的时候 才会执行else
- 循环不可以使用continue和break 来控制循环的执行
三、注释标签(多行注释)
作用:
- 代码调试
- 简介说明
格式:
{# 这是一个注释 #}
注意:
注释的代码都不会在浏览器的HTML页面中显示出来
四、文件包含 include
概述:
include语句 可以把一个模板引入到另外一个模板中 类似于把一个不安的代码 copy到另外一个模板的指定位置中 实现模板代码的复用
实例:
head.html
<nav>我是头部</nav>
footer.html
<footer>底部</footer>
test_include.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
padding:0;
margin: 0;
}
nav{
width:100%;
height: 40px;
background-color: #000;
color: #fff;
}
footer{
width:100%;
height: 100px;
background-color: orange;
position: absolute;
bottom:0;
}
</style>
</head>
<body>
{% include 'common/head.html' %}
<div>我是中间主体部分</div>
{% include 'common/footer.html' %}
</body>
</html>
注意:
导入的文件的代码一定是当前需要的 不要添加任何其它的代码 包括主体结构 否则会将当前页面的所有代码包含进来
五、宏 macro
概述:
类似于我们python的函数 可以封装一段特定功能的HTML代码段
主体结构:
# 定义宏
{% amcro 宏的名称([参数[参数...]]) %}
...
{% endmacro %}
# 调用宏
{{ 宏名称([参数[参数...]]) }}
(1) 宏的简单使用
{% macro test() %}
当你调用宏的时候就会看到我了
{% endmacro %}
{{ test() }}
{{ test() }}
(2) 宏的传参使用
<h4>测试宏的传参的使用</h4>
{#{% macro test_arg(name,age) %}#}
{#形参默认值#}
{% macro test_arg(name='lucky',age=18) %}
<p>我叫:{{ name }} 我今年{{ age }}岁了</p>
{% endmacro %}
{#调用不传实参 正常使用#}
{#{{ test_arg() }}#}
{#传实参#}
{#{{ test_arg('lucky',18) }}#}
{{ test_arg('张三') }}
(3) 宏的导入
common/public_macro.html
{% macro test_arg(name='lucky',age=18) %}
<p>我叫:{{ name }} 我今年{{ age }}岁了</p>
{% endmacro %}
导入使用:
<h4>测试宏的导入使用</h4>
{#第一种导入方式#}
{% from 'common/public_macro.html' import test_arg %}
{{ test_arg() }}
{#起别名#}
{% from 'common/public_macro.html' import test_arg as my_tag %}
{{ my_tag() }}
{% import 'common/public_macro.html' as public_macro %}
{{ public_macro.test_arg('张三') }}
注意:
不能在宏定义的上方去调用
六、模板继承
flask中的模板可以继承 通过继承可以把模板中许多重复出现的元素抽取出来 放在父模板中 并且父模板通过定义 block给子模板开一个口 子模板根据需要 在实现这个block
用到的标签
-
继承
extends
-
替换
block
实例:
创建commone/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}Title{% endblock %}</title>
<style>
*{
padding: 0;
margin: 0;
list-style: none;
}
ul,footer{
width: 100%;
background-color: #000;
}
li{
width:150px;
height: 30px;
text-align: center;
line-height: 30px;
color: #fff;
}
footer{
height: 30px;
position: absolute;
bottom:0;
color:#fff;
}
</style>
</head>
<body>
<nav>
<ul>
<li>首页</li>
<li>首页</li>
</ul>
</nav>
<div class="con">
{% block con %}
<p>我是显示主题内容的位置</p>
{% endblock %}
</div>
<footer>
我是底部栏
</footer>
</body>
</html>
index.html集成common/base.html的模板
{% extends 'common/base.html' %}
{% block title %}
首页
{% endblock %}
{% block con %}
{{ super() }}
<h2>我是index模板替换的内容</h2>
{% endblock %}
<p>在block之外的内容不会显示出来</p>
路由和视图函数
# 测试base模板使用的路由地址
@app.route('/test_base/')
def test_base():
return render_template('common/base.html')
@app.route('/')
def index():
return render_template('index.html')
注意:
-
在父模板中如果添加了block 在子模板中没有进行替换 则正常显示 没有任何影响
-
在子模板进行block替换的位置以外的地方 添加任何代码都不会被显示出来
-
如果在子模板中进行了父模板某个block内容的替换 如果想将替换的内容在显示出来 则调用变量 super()方法
{{ super() }}
-
父模板中如果存在的block越多 那么就证明父模板越灵活
七、flask-bootstrap扩展库
安装:
pip install flask-bootstrap
使用:
from flask import Flask,render_template
from flask_script import Manager
from flask_bootstrap import Bootstrap
app = Flask(__name__)
# 实例化对象
Bootstrap(app)
manager = Manager(app)
查看flask-bootstrap扩展库的base.html
{% block doc -%}
<!DOCTYPE html>
<html{% block html_attribs %}{% endblock html_attribs %}>
{%- block html %}
<head>
{%- block head %}
<title>{% block title %}{{title|default}}{% endblock title %}</title>
{%- block metas %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{%- endblock metas %}
{%- block styles %}
<!-- Bootstrap -->
<link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet">
{%- endblock styles %}
{%- endblock head %}
</head>
<body{% block body_attribs %}{% endblock body_attribs %}>
{% block body -%}
{% block navbar %}
{%- endblock navbar %}
{% block content -%}
{%- endblock content %}
{% block scripts %}
<script src="{{bootstrap_find_resource('jquery.js', cdn='jquery')}}"></script>
<script src="{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script>
{%- endblock scripts %}
{%- endblock body %}
</body>
{%- endblock html %}
</html>
{% endblock doc -%}
每个block的作用
block | 说明 |
---|---|
doc | 整个HTML文档 |
html | html内部所有代码 |
head | head标签 |
title | title标签 |
styles | 引入css样式 |
metas | 一组meta标签 |
body | body标签 |
navbar | 用户自定义当好条 |
content | 用户自定义内容 |
scripts | 用户定义的js |
简单使用flask-bootstrap的base
{% extends 'bootstrap/base.html' %}
{% block title %}
boot_base
{% endblock %}
{% block content %}
继承了flask_bootstrap的base模板的子模板
{% endblock %}
路由和视图函数
# 测试bootstrap的基础模板
@app.route('/test_boot_base/')
def test_boot_base():
return render_template('common/boot_base.html')
定义项目基础模板
概述:
一个项目中 很多页面都相似 只有细微差别 如果每个都定制 那么就会有大量的重复的代码 为了简化这种工作 我们通常为项目定制一个基础模板(base) 让它集成子bootstrap的基础模板 其它页面集成该基础模板 只需稍微定制即可
实例:
{% extends 'bootstrap/base.html' %}
{% block title %}
boot_base
{% endblock %}
{% block navbar %}
<nav class="navbar navbar-inverse" style="border-radius: 0">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">
<span class="glyphicon glyphicon-fire" aria-hidden="true"></span>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">首页 <span class="sr-only">(current)</span></a></li>
<li><a href="#">发表博客</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<li><a href="#">登录</a></li>
<li><a href="#">注册</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% endblock %}
{% block content %}
<div class="container">
{% block page_content %}
继承了flask_bootstrap的base模板的子模板
{% endblock %}
</div>
{% endblock %}
配置家在本地bootstrap的样式 不再从网络获取
app = Flask(__name__)
# 加载使用本地的样式
app.config['BOOTSTRAP_SERVE_LOCAL'] = True
# 实例化对象
Bootstrap(app)
manager = Manager(app)
八、错误页面定制
(1) 添加视图函数
# 错误状态码捕获
@app.errorhandler(404)
def page_not_found(e):
return render_template('error.html',title="404_NOT_FOUND",info="您访问的地址被外星人抓走了...")
@app.errorhandler(500)
def server_error(e):
return render_template('error.html',title="500_SERVER_ERROR",info='您的访问太热情了 请稍后访问...')
(2) 错误模板
{% extends 'common/boot_base.html' %}
{% block title %}
{{ title }}
{% endblock %}
{% block page_content %}
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>{{ title }}</strong> {{ info }}
</div>
{% endblock %}
九、模板中url_for的使用
概述:
根据视图函数构造路由地址
-
根据视图函数名反向构造路由地址,路由需要的直接构造,多出来的参数以GET传递
url_for('var', name='lucky', pwd='123456')
/var/?name=lucky&pwd=123456,不完整,没有主机和端口
-
若需要构造完整的外部链接,需要添加_extenal=True的参数
url_for('var', name='xiaoming', pwd='123456', _external=True)
http://127.0.0.1:5000/var/?name=xiaoming&pwd=123456
-
通常网站中的点击链接都是使用url_for构造的,如:
<li><a href="{{ url_for('register') }}">注册</a></li> #register 为视图函数名
视图函数代码
# 一个测试的路由地址
@app.route('/test/')
def test():
return '测试路由地址'
# 一个测试的路由地址 带传参的
@app.route('/test2/<arg>/')
def test2(arg):
return '测试路由地址参数arg值为{}'.format(arg)
模板代码
<dl>
<dt>相对地址</dt>
<dd>{{ url_for('test') }}</dd>
<dt>绝对地址</dt>
<dd>{{ url_for('test',_external=True) }}</dd>
<dt>绝对地址get传参</dt>
<dd>{{ url_for('test',name='lucky',age=18,_external=True) }}</dd>
<dt>绝对地址路由传参</dt>
<dd>{{ url_for('test2',arg='arg',_external=True) }}</dd>
<dt>绝对地址路由传参并添加到超链接中</dt>
<dd><a href="{{ url_for('test2',arg='arg',_external=True) }}">test2</a></dd>
</dl>
注意:
如果构造的视图函数在某个蓝本中 那么在模板中构造路由地址和视图函数中一样
{{ url_for(‘蓝本名称.视图函数名’) }}
十、加载静态资源
静态资源文件?
css js img 统称为静态资源文件
(1) flask框架中静态资源默认为目录为static 项目目录结构为
project/
templates/ 模板目录
static/ 静态资源目录
img/
timg.jpg
css/
js
manage.py 启动文件
(2) 加载图片资源
实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="icon" href="{{ url_for('static',filename="img/timg.jpeg") }}">
</head>
<body>
<h2>首页</h2>
<h4>升仕310x摩托车</h4>
<img src="{{ url_for('static',filename='img/timg.jpeg',_external=True) }}" alt="">
</body>
</html>
十一、视图传递多个参数
(1) 使用全局变量g
导入:
from flask import g
视图函数中
@app.route('/')
def index():
g.name = 'lucky'
g.age = 18
return render_template('index.html')
模板中
<h4>测试传递多个参数</h4>
<p>{{ g.name }}</p>
<p>{{ g.age }}</p>
(2) 使用**locals()
视图函数中
@app.route('/')
def index():
name = 'lucky'
age = 18
print(locals())
return render_template('index.html',**locals())
模板中
<p>{{ name }}</p>
<p>{{ age }}</p>
(3) 使用字典传参
视图函数中
@app.route('/')
def index():
return render_template('index.html',**{'name':'lucky','age':18})
模板中
<p>{{ name }}</p>
<p>{{ age }}</p>
(4) 原始传参
@app.route('/')
def index():
return render_template('index.html',name='lucky',age=18)
十二、过滤器
概述:
过滤器相当于是一个python函数 把当前变量传入到过滤器中 过滤器根据自己的功能进行过滤 并返回相应的值 在输出到模板
Jinja2中内置了许多过滤器 以下为常用过滤器
使用:
不传参
{{ var|过滤器名称 }}
传参
{{ var|过滤器名称(参数…) }}
(1) 过滤器
-
abs 返回一个数值的绝对值
{{ num|abs }}
-
default 默认值 当变量不存在则执行默认值 如果想bool的假也执行 需要以下实例进行改变
<p>{{ num|default('default') }}</p> <p>{{ xxx|default('default') }}</p>
{{ bool|default('default',boolean=True) }}
-
first 返回序列的第一个元素
-
last 返回序列的最后一个元素
-
format 格式化字符串
{{ '我叫%s 我今年%d岁了 我的存款为 %.2f元'|format('lucky',18,123456) }}
-
length 返回一个序列或者字典的长度
-
join将一个序列拼接成字符串
{{ List|join('-') }}
-
int 将值转换为int类型
-
float 转换为浮点型
-
string 转换为字符串
-
list 转换为列表
-
lower 转换为小写
-
upper 转换为大写
-
replace 替换
-
striptags 删除字符串中的所有HTML标签
-
safe 默认为了安全考虑 是不会解析html代码的 可以使用safe进行解析输出
-
trim 删除字符串俩侧的空白字符
(2) 自定义过滤器
实现的功能:当内容超出给定的长度以后 显示省略号
方式一
通过flask应用对象的add_templater_filter方法
视图函数
# 超出固定长度 显示省略号
def show_ellipsis(Str,length=5):
if len(Str)>length:
Str = Str[0:length]+'...'
return Str
app.add_template_filter(show_ellipsis)
方式二
通过装饰器来实现自定义过滤器
# 使用过滤器实现
@app.template_filter()
def show_ellipsis(Str,length=5):
if len(Str)>length:
Str = Str[0:length]+'...'
return Str
模板中使用
<h4>自定义过滤器的测试</h4>
<p>{{ name|show_ellipsis }}</p>