前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Flask笔记】4大章md笔记第5篇:Flask模板的进阶使用和案例(图文和代码)

【Flask笔记】4大章md笔记第5篇:Flask模板的进阶使用和案例(图文和代码)

原创
作者头像
程序员一诺
发布2023-11-25 20:27:38
1960
发布2023-11-25 20:27:38
举报
文章被收录于专栏:知识集合知识集合
本文的主要内容:flask视图&路由、虚拟环境安装、路由各种定义、状态保持、cookie、session、模板基本使用、过滤器&自定义过滤器、模板代码复用:宏、继承/包含、模板中特有变量和函数、Flask-WTF 表单、CSRF、数据库操作、ORM、Flask-SQLAlchemy、增删改查操作、案例、蓝图、单元测试

分享全套Flask笔记和代码感兴趣自取: 请移步这里

方便同学们预览,笔记总目录:共 4 章,42 子模块

模板

  • 基本使用
  • 过滤器&自定义过滤器
  • 控制代码块
  • 宏、继承、包含
  • Flask 的模板中特有变量和方法
  • web表单
  • CSRF

学习目标

  • 能够写出 jinja2 中变量代码块和控制代码块的格式
  • 能够写出在模板中字典,列表的取值方式
  • 能够写出数组反转的自定义过滤器(使用1种方式即可)
  • 能够说出Flask中模板代码复用的三种方式
  • 能够使用代码实现模板继承的功能
  • 能够说出可以在模板中直接使用的 Flask 变量和函数
  • 能够使用 Flask-WTF 扩展实现注册表单
  • 能够说出 CSRF 原理

模板的使用

  • 在项目下创建 templates 文件夹,用于存放所有的模板文件,并在目录下创建一个模板html文件 temp_demo1.html
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容
</body>
</html>
  • 设置 templates 文件夹属性以便能够在代码中有智能提示
  • 设置 html 中的模板语言,以便在 html 有智能提示
  • 创建视图函数,将该模板内容进行渲染返回
代码语言:javascript
复制
@app.route('/')
def index():
    return render_template('temp_demo1.html')

访问:http://127.0.0.1:5000/ 运行测试

  • 代码中传入字符串,列表,字典到模板中
代码语言:javascript
复制
@app.route('/')
def index():
    # 往模板中传入的数据
    my_str = 'Hello 黑马程序员'
    my_int = 10
    my_array = [3, 4, 2, 1, 7, 9]
    my_dict = {
        'name': 'xiaoming',
        'age': 18
    }
    return render_template('temp_demo1.html',
                           my_str=my_str,
                           my_int=my_int,
                           my_array=my_array,
                           my_dict=my_dict
                           )
  • 模板中代码
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我的模板html内容
<br/>{{ my_str }}
<br/>{{ my_int }}
<br/>{{ my_array }}
<br/>{{ my_dict }}
?
</body>
</html>
  • 运行效果

?

我的模板html内容 Hello 黑马程序员 10 [3, 4, 2, 1, 7, 9] {'name': 'xiaoming', 'age': 18}Code injected by live-server * 相关运算,取值

?

代码语言:javascript
复制
<br/> my_int + 10 的和为:{{ my_int + 10 }}
<br/> my_int + my_array第0个值的和为:{{ my_int + my_array[0] }}
<br/> my_array 第0个值为:{{ my_array[0] }}
<br/> my_array 第1个值为:{{ my_array.1 }}
<br/> my_dict 中 name 的值为:{{ my_dict['name'] }}
<br/> my_dict 中 age 的值为:{{ my_dict.age }}
  • 结果
代码语言:javascript
复制
my_int + 10 的和为:20 
my_int + my_array第0个值的和为:13 
my_array 第0个值为:3 
my_array 第1个值为:4 
my_dict 中 name 的值为:xiaoming 
my_dict 中 age 的值为:18

过滤器

过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用 Python 中的某些方法,那么这就用到了过滤器。

使用方式:

  • 过滤器的使用方式为:变量名 | 过滤器。
代码语言:javascript
复制
{{variable | filter_name(*args)}}
  • 如果没有任何参数传给过滤器,则可以把括号省略掉
代码语言:javascript
复制
{{variable | filter_name}}
  • 如:``,这个过滤器的作用:把变量variable 的值的首字母转换为大写,其他字母转换为小写

链式调用

在 jinja2 中,过滤器是可以支持链式调用的,示例如下:

代码语言:javascript
复制
{{ "hello world" | reverse | upper }}

常见内建过滤器

字符串操作

  • safe:禁用转义
代码语言:javascript
复制
<p>{{ '<em>hello</em>' | safe }}</p>
  • capitalize:把变量值的首字母转成大写,其余字母转小写
代码语言:javascript
复制
<p>{{ 'hello' | capitalize }}</p>
  • lower:把值转成小写
代码语言:javascript
复制
<p>{{ 'HELLO' | lower }}</p>
  • upper:把值转成大写
代码语言:javascript
复制
<p>{{ 'hello' | upper }}</p>
  • title:把值中的每个单词的首字母都转成大写
代码语言:javascript
复制
<p>{{ 'hello' | title }}</p>
  • reverse:字符串反转
代码语言:javascript
复制
<p>{{ 'olleh' | reverse }}</p>
  • format:格式化输出
代码语言:javascript
复制
<p>{{ '%s is %d' | format('name',17) }}</p>
  • striptags:渲染之前把值中所有的HTML标签都删掉
代码语言:javascript
复制
<p>{{ '<em>hello</em>' | striptags }}</p>

列表操作

  • first:取第一个元素
代码语言:javascript
复制
<p>{{ [1,2,3,4,5,6] | first }}</p>
  • last:取最后一个元素
代码语言:javascript
复制
<p>{{ [1,2,3,4,5,6] | last }}</p>
  • length:列表长度
代码语言:javascript
复制
<p>{{ [1,2,3,4,5,6] | length }}</p>
  • sum:列表求和
代码语言:javascript
复制
<p>{{ [1,2,3,4,5,6] | sum }}</p>
  • sort:列表排序
代码语言:javascript
复制
<p>{{ [6,2,3,1,5,4] | sort }}</p>

语句块过滤

代码语言:javascript
复制
{% filter upper %}
    #一大堆文字#
{% endfilter %}

自定义过滤器

过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。自定义过滤器有两种实现方式:

  • 一种是通过Flask应用对象的 add_template_filter 方法
  • 通过装饰器来实现自定义过滤器

重要:自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。

需求:添加列表反转的过滤器

方式一

通过调用应用程序实例的 add_template_filter 方法实现自定义过滤器。该方法第一个参数是函数名,第二个参数是自定义的过滤器名称:

代码语言:javascript
复制
def do_listreverse(li):
    # 通过原列表创建一个新列表
    temp_li = list(li)
    # 将新列表进行返转
    temp_li.reverse()
    return temp_li
?
app.add_template_filter(do_listreverse,'lireverse')
方式二

用装饰器来实现自定义过滤器。装饰器传入的参数是自定义的过滤器名称。

代码语言:javascript
复制
@app.template_filter('lireverse')
def do_listreverse(li):
    # 通过原列表创建一个新列表
    temp_li = list(li)
    # 将新列表进行返转
    temp_li.reverse()
    return temp_li
  • 在 html 中使用该自定义过滤器
代码语言:javascript
复制
<br/> my_array 原内容:{{ my_array }}
<br/> my_array 反转:{{ my_array | lireverse }}
  • 运行结果
代码语言:javascript
复制
my_array 原内容:[3, 4, 2, 1, 7, 9] 
my_array 反转:[9, 7, 1, 2, 4, 3]

控制代码块

控制代码块主要包含两个:

代码语言:javascript
复制
- if/else if /else / endif
- for / endfor

if语句

Jinja2 语法中的if语句跟 Python 中的 if 语句相似,后面的布尔值或返回布尔值的表达式将决定代码中的哪个流程会被执行:

代码语言:javascript
复制
{%if user.is_logged_in() %}
    <a href='/logout'>Logout</a>
{% else %}
    <a href='/login'>Login</a>
{% endif %}

过滤器可以被用在 if 语句中:

代码语言:javascript
复制
{% if comments | length > 0 %}
    There are {{ comments | length }} comments
{% else %}
    There are no comments
{% endif %}

循环

  • 我们可以在 Jinja2 中使用循环来迭代任何列表或者生成器函数
代码语言:javascript
复制
{% for post in posts %}
    <div>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text | safe }}</p>
    </div>
{% endfor %}
  • 循环和if语句可以组合使用,以模拟 Python 循环中的 continue 功能,下面这个循环将只会渲染post.text不为None的那些post:
代码语言:javascript
复制
{% for post in posts if post.text %}
    <div>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text | safe }}</p>
    </div>
{% endfor %}
  • 在一个 for 循环块中你可以访问这些特殊的变量:

变量

描述

loop.index

当前循环迭代的次数(从 1 开始)

loop.index0

当前循环迭代的次数(从 0 开始)

loop.revindex

到循环结束需要迭代的次数(从 1 开始)

loop.revindex0

到循环结束需要迭代的次数(从 0 开始)

loop.first

如果是第一次迭代,为 True 。

loop.last

如果是最后一次迭代,为 True 。

loop.length

序列中的项目数。

loop.cycle

在一串序列间期取值的辅助函数。见下面示例程序。

  • 在循环内部,你可以使用一个叫做loop的特殊变量来获得关于for循环的一些信息
    • 比如:要是我们想知道当前被迭代的元素序号,并模拟Python中的enumerate函数做的事情,则可以使用loop变量的index属性,例如:
代码语言:javascript
复制
{% for post in posts%}
{{loop.index}}, {{post.title}}
{% endfor %}
  • 会输出这样的结果
代码语言:javascript
复制
1, Post title
2, Second Post
  • cycle函数会在每次循环的时候,返回其参数中的下一个元素,可以拿上面的例子来说明:
代码语言:javascript
复制
{% for post in posts%}
{{loop.cycle('odd','even')}} {{post.title}}
{% endfor %}
  • 会输出这样的结果:
代码语言:javascript
复制
odd Post Title
even Second Post

示例程序

  • 实现的效果
  • 准备数据
代码语言:javascript
复制
# 只显示4行数据,背景颜色依次为:黄,绿,红,紫
  
  
my_list = [
    {
        "id": 1,
        "value": "我爱工作"
    },
    {
        "id": 2,
        "value": "工作使人快乐"
    },
    {
        "id": 3,
        "value": "沉迷于工作无法自拔"
    },
    {
        "id": 4,
        "value": "日渐消瘦"
    },
    {
        "id": 5,
        "value": "以梦为马,越骑越傻"
    }
]
  • 模板代码
代码语言:javascript
复制
{% for item in my_list if item.id != 5 %}
    {% if loop.index == 1 %}
        <li style="background-color: orange">{{ item.value }}</li>
    {% elif loop.index == 2 %}
        <li style="background-color: green">{{ item.value }}</li>
    {% elif loop.index == 3 %}
        <li style="background-color: red">{{ item.value }}</li>
    {% else %}
        <li style="background-color: purple">{{ item.value }}</li>
    {% endif %}
{% endfor %}

模板代码复用

在模板中,可能会遇到以下情况:

  • 多个模板具有完全相同的顶部和底部内容
  • 多个模板中具有相同的模板代码内容,但是内容中部分值不一样
  • 多个模板中具有完全相同的 html 代码块内容

像遇到这种情况,可以使用 JinJa2 模板中的 宏、继承、包含来进行实现

对宏(macro)的理解:

  • 把它看作 Jinja2 中的一个函数,它会返回一个模板或者 HTML 字符串
  • 为了避免反复地编写同样的模板代码,出现代码冗余,可以把他们写成函数以进行重用
  • 需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复

使用

  • 定义宏
代码语言:javascript
复制
{% macro input(name,value='',type='text') %}
    <input type="{{type}}" name="{{name}}"
        value="{{value}}" class="form-control">
{% endmacro %}
  • 调用宏
代码语言:javascript
复制
{{ input('name' value='zs')}}
  • 这会输出
代码语言:javascript
复制
<input type="text" name="name"
    value="zs" class="form-control">
  • 把宏单独抽取出来,封装成html文件,其它模板中导入使用,文件名可以自定义macro.html
代码语言:javascript
复制
{% macro function(type='text', name='', value='') %}
<input type="{{type}}" name="{{name}}"
value="{{value}}" class="form-control">
?
{% endmacro %}
  • 在其它模板文件中先导入,再调用
代码语言:javascript
复制
{% import 'macro.html' as func %}
{% func.function() %}

代码演练

  • 使用宏之前代码
代码语言:javascript
复制
<form>
    <label>用户名:</label><input type="text" name="username"><br/>
    <label>身份证号:</label><input type="text" name="idcard"><br/>
    <label>密码:</label><input type="password" name="password"><br/>
    <label>确认密码:</label><input type="password" name="password2"><br/>
    <input type="submit" value="注册">
</form>
  • 定义宏
代码语言:javascript
复制
{#定义宏,相当于定义一个函数,在使用的时候直接调用该宏,传入不同的参数就可以了#}
{% macro input(label="", type="text", name="", value="") %}
<label>{{ label }}</label><input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}
  • 使用宏
代码语言:javascript
复制
<form>
    {{ input("用户名:", name="username") }}<br/>
    {{ input("身份证号:", name="idcard") }}<br/>
    {{ input("密码:", type="password", name="password") }}<br/>
    {{ input("确认密码:", type="password", name="password2") }}<br/>
    {{ input(type="submit", value="注册") }}
</form>

模板继承

模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

  • 标签定义的内容
代码语言:javascript
复制
{% block top %} {% endblock %}
  • 相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
  • 子模板使用 extends 指令声明这个模板继承自哪个模板
  • 父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()

父模板

  • base.html
代码语言:javascript
复制
{% block top %}
  顶部菜单
{% endblock top %}
?
{% block content %}
{% endblock content %}
?
{% block bottom %}
  底部
{% endblock bottom %}

子模板

  • extends指令声明这个模板继承自哪
代码语言:javascript
复制
{% extends 'base.html' %}
{% block content %}
 需要填充的内容
{% endblock content %}
  • 模板继承使用时注意点:
    • 不支持多继承
    • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
    • 不能在一个模板文件中定义多个相同名字的block标签。
    • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。

未完待续 下一期下一章

全套笔记直接地址: 请移步这里

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 分享全套Flask笔记和代码感兴趣自取: 请移步这里
    • 方便同学们预览,笔记总目录:共 4 章,42 子模块
    • 模板
    • 学习目标
    • 模板的使用
    • 过滤器
      • 链式调用
        • 常见内建过滤器
          • 字符串操作
          • 列表操作
          • 语句块过滤
          • 需求:添加列表反转的过滤器
      • 自定义过滤器
      • 控制代码块
        • if语句
          • 循环
            • 示例程序
            • 模板代码复用
              • 使用
                • 代码演练
                • 模板继承
                  • 父模板
                    • 子模板
                      • 未完待续 下一期下一章
                      • 全套笔记直接地址: 请移步这里
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                      http://www.vxiaotou.com