Flask模版详解

发布于:2024-05-06 ⋅ 阅读:(32) ⋅ 点赞:(0)

概述

模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask 使用了一个名为 Jinja2 的强大模板引擎

形式最简单的 Jinja2 模板就是一个包含响应文本的文件,例如:

<h1>Hello, {{ name }}!</h1>

Jinja2模板引擎

渲染模版的步骤

1、前端创建模版

默认情况下,Flask 在程序文件夹中的 templates 子文件夹中寻找模板。例如把前面定义的模板保存在templates 文件夹中,命名为index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
</body>
</html>

2、后端渲染模版

@app.route('/')
def index():
    name = "dahezhiquan"
    return render_template('index.html', name=name)

Flask 提供的 render_template 函数把 Jinja2 模板引擎集成到了程序中。render_template 函数的第一个参数是模板的文件名。随后的参数都是键值对,表示模板中变量对应的真实值。在这段代码中,第二个模板收到一个名为 name 的变量

左边的“name”表示参数名,就是模板中使用的占位符;右边的“name”是当前作用域中的变量,表示同名参数的值

3、运行程序,查看模版渲染效果

image.png

变量

在模板中使用的{{ name }}结构表示一个变量,它是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取

Jinja2 能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。在模板中使用变量的一些示例如下:

<!-- 从字典中获取值 -->
<p>A value from a dictionary: {{ mydict['key'] }}.</p>

<!-- 从列表中获取值 -->
<p>A value from a list: {{ mylist[3] }}.</p>

<!-- 从列表中获取值,使用变量作为索引 -->
<p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p>

<!-- 调用对象的方法 -->
<p>A value from an object's method: {{ myobj.somemethod() }}.</p>

同时还可以使用过滤器修改变量,过滤器名添加在变量名之后,中间使用竖线分隔,例如,下述模板以首字母大写形式显示变量 name 的值:

Hello, {{ name|capitalize }}

Jinja2 提供的部分常用过滤器:

  • safe:标记变量为安全,使得它们不会被转义。例如:{{ my_html_content | safe }}
  • capitalize:将字符串的首字母大写。例如:{{ my_string | capitalize }}
  • lower:将字符串转换为小写。例如:{{ my_string | lower }}
  • upper:将字符串转换为大写。例如:{{ my_string | upper }}
  • title:将字符串中每个单词的首字母大写。例如:{{ my_string | title }}
  • trim:除字符串两侧的空白字符。例如:{{ my_string | trim }}
  • striptags:移除所有 HTML 标签,并仅保留纯文本内容

safe 过滤器值得特别说明一下。默认情况下,出于安全考虑,Jinja2 会转义所有变量。例如,如果一个变量的值为 ‘<h1>Hello</h1>’,Jinja2 会将其渲染成’&lt;h1&gt;Hello&lt;/h1&gt;',浏览器能显示这个 h1 元素,但不会进行解释。很多情况下需要显示变量中存储的 HTML 代码,这时就可使用 safe 过滤器。千万别在不可信的值上使用 safe 过滤器,例如用户在表单中输入的文本。

控制结构

Jinja2 提供了多种控制结构,可用来改变模板的渲染流程,例如:

{% if user %}
    Hello, {{ user }}!
{% else %}
    Hello, stranger!
{% endif %}

另一种常见需求是在模板中渲染一组元素。下例展示了如何使用 for 循环实现这一需求:

<ul>
{% for comment in comments %}
    <li>{{ comment }}</li>
{% endfor %}
</ul>

Jinja2 还支持宏。宏类似于 Python 代码中的函数。例如:

{% macro render_comment(comment) %}
    <li>{{ comment }}</li>
{% endmacro %}

<ul>
{% for comment in comments %}
    {{ render_comment(comment) }}
{% endfor %}
</ul>

在这个模板中,{% macro render_comment(comment) %} 定义了一个宏,它接受一个名为 comment 的参数,并返回一个 <li> 标签,其中包含评论内容。{% endmacro %} 表示宏定义的结束。

然后,在循环中,{% for comment in comments %} 遍历评论列表,并对每个评论调用 render_comment 宏来生成相应的 HTML。每次循环迭代时,宏将被展开,生成一个包含评论内容的列表项,并将其插入到 <ul> 中。

这种使用宏的方式可以使模板更具可重用性和可维护性,特别是当需要在多个地方使用相同的 HTML 结构时。

需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复:

{% include 'common.html' %}

另一种重复使用代码的强大方式是模板继承,它类似于 Python 代码中的类继承。首先,创建一个名为 base.html 的基模板:

<html lang="zh-CN">
<head>
    {% block head %}
        <title>{% block title %}{% endblock %} - My Application</title>
    {% endblock %}
</head>
<body>
    {% block body %}
    {% endblock %}
</body>
</html>

在这个模板中,{% block head %} {% block body %} 标记定义了两个可替换的块,它们分别用于定义页面头部和主体内容

下面这个示例是基模板的衍生模板:

{% extends "base.html" %}

{% block title %}
    Index
{% endblock %}

{% block head %}
    {{ super() }}
    <style>
    </style>
{% endblock %}

{% block body %}
    <h1>Hello, World!</h1>
{% endblock %}

在这个子模板中,使用了 {% extends "base.html" %} 来继承基础模板。然后,重写了 title 块,将页面标题设置为 “Index”。接着,重写了 head 块,在原有的基础上使用了 super() 函数来调用基础模板中定义的内容,并添加了特定页面的样式。最后,重写了 body 块,定义了页面的主体内容

image.png

自定义错误页面

如果你在浏览器的地址栏中输入了不可用的路由,那么会显示一个状态码为 404 的错误页面
像常规路由一样,Flask 允许程序使用基于模板的自定义错误页面。最常见的错误代码有两个:404,客户端请求未知页面或路由时显示;500,有未处理的异常时显示

1、编写视图代码

@app.errorhandler(404)
def page_not_found(e):
    return render_template('errors/404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('errors/500.html'), 500

2、编写错误模版代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>404</title>
  </head>
  <body>
    <h1>404</h1>
  </body>
</html>

3、此时访问一个不存在的URL,会呈现自定义的404模版页面

image.png

链接

任何具有多个路由的程序都需要可以连接不同页面的链接,例如导航条。

在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的依赖关系。如果重新定义路由,模板中的链接可能会失效。

为了避免这些问题,Flask 提供了 url_for() 辅助函数,它可以使用程序 URL 映射中保存的信息生成 URL。

url_for('index') 得到的结果是 /。调用 url_for('index', _external=True) 返回的则是绝对地址,例如:http://127.0.0.1:5000/

使用 url_for() 生成动态地址时,将动态部分作为关键字参数传入。例如:

url = url_for('index', name='john', _external=True)

上述代码的返回结果是,http://127.0.0.1:5000/index?name=john

静态文件

Web 程序不是仅由 Python 代码和模板组成。大多数程序还会使用静态文件,例如HTML代码中引用的图片、JavaScript 源码文件和 CSS

默认设置下,Flask 在程序根目录中名为 static 的子目录中寻找静态文件。如果需要,可在 static 文件夹中使用子文件夹存放文件

1、在项目的static文件夹中上传icon网页图标文件

image.png

2、在base.html中使用favicon.ico

<html lang="zh-CN">
<head>
    {% block head %}
        <title>{% block title %}{% endblock %} - My Application</title>
    {% endblock %}
    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
    <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
</head>
<body>
    {% block body %}
    {% endblock %}
</body>
</html>

3、icon图标设置成功

image.png