Flask模板简介

Flask模板

一、jinja2 模板介绍

jinja2模板是一个日本人开发的,Jinja2的开发是参考了django的模板,跟django模板由很多类似的地 方,但它扩 展了一种表达性语言,提供了一套更强大的工具

jinja2特性

沙箱中执行

强大的 HTML 自动转义系统保护系统免受 XSS 攻击

模板继承

及时编译最优的 python 代码

可选提前编译模板的时间

易于调试。异常的行数直接指向模板中的对应行。

可配置的语法

安装Flask的时候会自带安装jinja2 如果没有安装jinja2模板,可以使用下面命令安装:

pip install jinja2

二、模板渲染

1、 视图调用模板

在前一节课创建项目的时候已经讲过,模板目录的位置,下面我们来讲如何使用模板。 首先我们在项目目录下创建一个templates目录统一管理模板文件。 在视图中使用 render_templates 函数调用模板文件。

在templates目录下创建一个模板文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<br>
</body>
</html>

2、render_templates 调用模板

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def index():
    # 视图中调用模板
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

3、模板上下文

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
    # render_template 函数第一个参数是模板名称,后面的参数以key=value的形式,传给模板的变return render_template('index.html', name='python', age=26)

if __name__ == '__main__':
    app.run(debug=True)

注意:jinja2上下文传递,跟django中的是有区别的,django模板可以接收一个字典作为上下文,但是 jinja2中只

能以 key=value 的形式传递。

解决办法:

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def index():
    # render_template 函数第一个参数是模板名称,后面的参数以key=value的形式,传给模板的变
    量
    context = {'name': 'python',
    'age': 26}
    print(*context)
    # 将上下文定义成一个字典,在传递上下文的时候,先将其解包
    return render_template('index.html', **context)

if __name__ == '__main__':
    app.run(debug=True)

将上下文参数写成字典,传参时先解包。

三、基本语法

1、变量

{ { 变量 } }:装载一个变量,模板渲染的时候,会使用上下文传过来的变量值 模板中定义变量: 模板中添加变量,可以使用(set)语句。

全局变量

{% set name=‘python’ %}

之后就可以在页面文件中使用name这个变量了。在解释性语言中,变量的类型时运行时确定的,因 此,这里的变 量可以赋任何类型的值。

局部变量

可以使用with语句来创建一个内部的作用域,将set语句放在其中,这样创建的变量只在with代码块中 才有效

{% with b = ‘python’ %}

{{ b }}

{% endwith %}

b变量就只能在with标签间可以使用。

示例

前端

<!DOCTYPE html>
<html lang="en">
{% set price='88元' %}
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
{% with major = '软件开发' %}
{{ major }}
{% endwith %}
<h1>首页</h1>
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
<div>年龄:{{ price }}</div>
<div>专业:{{ major }}</div>
<br>
</body>
</html>

后端:

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/')
def index():
    # render_template 函数第一个参数是模板名称,后面的参数以key=value的形式,传给模板的变
    量
    context = {'name': 'python',
    'age': 26}
    print(*context)
    # 将上下文定义成一个字典,在传递上下文的时候,先将其解包
    return render_template('index.html', **context)

if __name__ == '__main__':
    app.run(debug=True)

2、控制语句

if语句:

{% if 条件1 %}
条件1成立时
{% elif 条件2 %}
条件2成立时
{% else %}
条件都不成立
{% endif %}

for语句:

{% for i in list %}
{{i}}
{% endfor %}

for中添加else,如果没有数据,将会输出else内容

for循环内置常量

循环不能使用countinue和break控制循环

示例:

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    {#条件判断#}
    <h1>条件判断</h1>
    {% if username %}
    <div>欢迎您{{ username }}</div>
    {% else %}
        div>登录|注册</div>
    {% endif %}
        
{#for循环#}
<h1>列表遍历</h1>
{% for dept in departments %}
    <div>{{ loop.index }}:{{ dept }}</div>
{% endfor %}
    
{#字典数据#}
<h1>字典遍历</h1>
{% for key,value in product.items() %}
    <div>{{ key }}:{{ value }}</div>
{% endfor %}
</body>
</html> 

后端

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
    context = {
    'username': 'hongfei',
    'departments': ['研发部', '人事部', '市场部', '采购部'],
    'product': {'name': "手机", "price": 3999, 'brand': "华为"}
    }
    # 将上下文定义成一个字典,在传递上下文的时候,先将其解包
    return render_template('index.html', **context)
if __name__ == '__main__':
    app.run(debug=True)

3、运算符

在jinja2模板中是支持直接运算。

四、过滤器

1、过滤器简介

过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至 格式化、运算等等,这就用到了过滤器。 过滤器的使用方式为:变量名 | 过滤器。

2、常用过滤器

常用过滤器如下:

字符串操作

列表操作:

数值操作:

3、自定义过滤器

当模板内置的过滤器不能满足需求,可以自定义过滤器。

自定义过滤器有两种实现方式:

第一种是通过Flask应用对象的add_template_filter方法。

第二种是通过 template_filter 装饰器来实现自定义过滤器。 自定义过滤器不能和内置过滤器重名,否则会将内置的过滤器覆盖掉。

方法一:

def filter_mod_1(num):
    return num % 2
# 该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。
app.add_template_filter(filter_mod_1, 'my_mod_1')

方法二:

# 通过装饰器,自定义过滤器,装饰器接受一个参数:过滤器名称
# 过滤器函数接收变量
@app.template_filter('my_mod')
def filter_mod(num):
    return num % 2

带参数过滤器

@app.template_filter('filter_list')
def filter_list(li, start, end):
    """自定义过滤器,自定义截取列表区间"""
    return li[start:end]

在模板中调用传参数过滤器后面加小括号,就跟python调用方法一样:

{{a|my_mod}} {#没参数#}

{{b|filter_list(2,5)}} {# 有参数#}

示例

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
{#字符串过滤器#}
<h3>字符串过滤器</h3>
{{ username|upper }}
{#列表过滤#}
<h3>列表过滤</h3>
{{ departments|length }}
{#数值过滤器#}
<h3>数值过滤</h3>
{{ score|round(1) }}
<h3>自定义过滤器</h3>
<div>{{ num|my_mod_1 }}</div>
<div>{{ departments|filter_list(1,3) }}</div>
</body>
</html>

后端

from flask import Flask, render_template
app = Flask(__name__)

# 自定义过滤器方式1
def filter_mod_1(num):
    return num % 2

# 该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。
app.add_template_filter(filter_mod_1, 'my_mod_1')

# 自定义过滤器方式2
@app.template_filter('filter_list')
def filter_list_(li, start, end):
    """自定义过滤器,自定义截取列表区间"""
    return li[start:end]

@app.route('/')
def index():
    context = {
    'username': 'hongfei',
    'departments': ['研发部', '人事部', '市场部', '采购部'],
    'score': 89.21,
    'num': 6
    }
    # 将上下文定义成一个字典,在传递上下文的时候,先将其解包
    return render_template('index.html', **context)
if __name__ == '__main__':
    app.run(debug=True)

五、Flask-WTF 扩展

在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表 单数据的功能。

使用地方扩需要先安装:

pip install flask-wtf

使用Flask-WTF需要配置参数SECRET_KEY, Flask-WTF提供 CSRF 防跨域请求攻击。 SECRET_KEY用来生 成加 密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌

1、WTForms 支持表单类型

2、WTForms常用验证函数

在Flask中如果不使用WTF扩展表单,那么只能在前端使用js验证,或者将数据传给服务器验证。这些验 证过程都需要开发人员去完成。使用扩展之后这些验证工作都交给第三方扩展去实现,开发人员无需再 写这些验证代码。

3、案例

使用Flask-WTF扩展表单

from flask import Flask, request, render_template, url_for, redirect
# 导入wtf扩展的表单类
from flask_wtf import FlaskForm
# 导入自定义表单需要的字段
from wtforms import SubmitField, StringField, PasswordField, \
SelectMultipleField, RadioField, BooleanField, SelectField
# 导入wtf扩展提供的表单验证器
from wtforms.validators import DataRequired, EqualTo, Length, Regexp

app = Flask(__name__)
app.config["SECRET_KEY"] = 'qdddd!=kt_8c*ohm$3k+hhhhejx&+=4avs#-a6+#@@'

class MyForm(FlaskForm):
    username = StringField(label='用户名',validators=[DataRequired("账号不能为空"),Length(4, 10, message='账号非法,请输入4~10位字符')])
    password = PasswordField(label='密码',validators=[DataRequired("密码不能为空"),Regexp('[0-9a-zA-Z!@#$%^&*]{6,16}')])
    check_password = PasswordField(label='确认密码',validators=[DataRequired("密码不能为空"),EqualTo('password', 'check_password')])
    gender = RadioField(label='性别', choices=[(1, '男'), (0, '女')], coerce=int)
    area = SelectField(label='地区', choices=[(1, '深圳'), (0, '广州'), (2, '北京')], coerce=int)
    submit = SubmitField()
                                                                   
@app.route('/register', methods=['get', 'post'])
def register():
    form = MyForm()
    if request.method == "GET":
        return render_template('register.html', form=form)
    elif request.method == "POST":
        if form.validate_on_submit(): # 如果验证通过
            # 获取数据
            username = form.username.data
            password = form.password.data
            check_password = form.check_password.data
            gender = form.gender.data
            print(username, password, check_password, gender)
            return 'ok'
        else: # 验证失败
            return render_template('register.html', form=form)
if __name__ == '__main__':
    app.run(debug=True)

模板:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/register" method="post">
{{ form.csrf_token() }}
{{ form.username.label }}:{{ form.username }}<br>
{{ form.password.label }}:{{ form.password }}<br>
{{ form.check_password.label }}:{{ form.check_password }}<br>
{{ form.gender.label }}:{{ form.gender }}<br>
{{ form.area.label }}:{{ form.area }}<br>
<p>{{ form.submit() }}</p>
</form>
</body>
</html>

六、模板继承

1、 模板继承

模板继承是为了重用模板页面中相同的部分。在网站开发中继承主要使用在网站的顶部菜单、底部。在 不同的页面 中可以少写很多重复代码。 模板继承主要有父模板,子模板。 父模板: 父模板中主要是写子模板重复代码,实际上就是一个普通模板文件。但是父模板中需要预留位置给子模 板填充。 在父模板中使用 block 标签给子模板预留位置。

{% block 名称 %}
预留子模板填充内容,父模板中也可以写默认内容
{% endblock %}

示例:

2、子模板继承

用 在子模板的第一行声明继承的父模板 子模板填充父模板中的内容,结束标签可以不填名称,但是为了方便阅读建议都写上

{% extends 'base.html' %}
{% block 父模板中的名称 % }
填充内容
{% endblock 父模板中的名称 % }

如果父模板中预留块中有默认内容,子模板没有填充的话将会使用默认内容,子模板一旦填充会覆盖父 模板中默认 内容。 要填充父模板,而且还需要调用父模板的内容使用 调用父模板内容。

子模板:

{% block body %}
<h6> 子模板填充的内容</h6>
{{ super() }}
{% endblock body %}

示例

base.html(模板父页面)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>小鱼商城</title>
</head>
<body>
<div class="header">
{% if username %}
<div class="login_btn ">
欢迎您:<em>[[ username ]]</em>
<span>|</span>
<a>退出</a>
</div>
{% else %}
<div lass="login_btn fl">
<a>登录</a>
<span>|</span>
<a>注册</a>
</div>
{% endif %}
</div>
{% block body %}
{#这里预留给子模板填充#}
基本界面
{% endblock body %}
<div class="footer">
<div class="foot_link">
<a href="#">关于我们</a>
<span>|</span>
<a href="#">联系我们</a>
<span>|</span>
<a href="#">招聘人才</a>
<span>|</span>
<a href="#">友情链接</a>
</div>
<p>CopyRight © 2021 北京小鱼商业股份有限公司 All Rights Reserved</p>
<p>电话:010-****888 京ICP备*******8</p>
</div>
</body>
</html>

index.html(模板子页面)

{% extends 'base.html' %}
{% block body %}
    商品列表
    {{ super() }}
{% endblock body %}

后端

from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
    return render_template('index.html')
if __name__ == '__main__':
    app.run(debug=True)

七、包含

Jinja2模板中,除了继承,还支持一种代码重用的功能,叫包含(Include)。它的功能相当于直接将另一 个模板 的内容直接copy进当前模板中。 包含(include)主要应用在一个模板内容太多的情况下,可以将其功能模块化分成多个模板,方便后期维 护开发。 包含:

{% include ‘header.html’ %}

包含在使用时,如果包含的模板文件不存在时,程序会抛出TemplateNotFound异常,可以加上ignore missing关键字。如果包含的模板文件不存在,会忽略这条include语句。 include的使用加上关键字ignore missing

{% include ‘header.html’ ignore missing %}

示例 对模板继承的示例进行调整

base.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>小鱼商城</title>
</head>
<body>
{% include('header.html') ignore missing %}
{% block body %}
{# 这里预留给子模板填充#}
基本界面
{% endblock body %}
{% include('footer.html') ignore missing %}
</body>
</html>

继承、包含相同点:

都可以实现代码的复用

继承、包含不同点:

继承(Block)的本质是代码填充,一般用于多个页面有重复代码。

包含(include)是本质是将其他模板代码直接复制过来,组成一个完整模板。

八、Flask 中的特殊变量

Flask 中的特殊变量可以直接在模板中使用,不需要通过上下文传递

特殊变量 说明

config 对象

config 对象就是Flask的config对象,也就是 app.config 对象。

request 对象

表示当前请求的 request 对象。

session 对象

表示当前请求的 session 对象

url_for 方法 反解析 直接通过视图函数名称,逆向生成url get_flashed_messages 方法 在视图中使用flash()函数传入的消息队列,在模板中使用 get_flashed_messages 取出

特殊变量与在视图中类似。

get_flashed_messages 方法使用:

get_flashed_messages 必须配合 flash()函数使用,相当于 flash函数是生产者生产数据, get_flashed_messages 是消费者将数据取出消费。

示例:

视图中使用flash函数添加数据:

import os
from flask import Flask, render_template, flash
app = Flask(__name__)
app.config["SECRET_KEY"] = os.urandom(24)
@app.route('/')
def hello_world():
    flash('python')
    flash('django')
    flash('flask')
    flash('爬虫')
    return render_template('index.html')
if __name__ == '__main__':
    app.run(debug=True)

模板中 get_flashed_messages方法消费数据

{% for i in get_flashed_messages() %}
	<p>{{ i }}<p>
{% endfor %}
    
    
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值