抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

flask深入学习之第二部分

模板

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

Jinja2模板引擎

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

1
<h1>Hello World!</h1>

或者是响应中包含变量,

1
<h1>Hello, {{ name }}!</h1> <!-- name即为其中的变量 -->

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def index():
return render_template('index.html')


@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
if __name__=='__main__':
app.run()

Flask提供的render_template函数把Jinja2模板引擎集成到了程序中。render_template函数的第一个参数是模板的文件名。随后的参数都是键值对,表示模板中变量对应的真实值。在这段代码中,第二个模板收到一个名为name的变量。在模板中使用的结构表示一个变量,它是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取。Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。

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

1
Hello, {{ name|capitalize }}

下表为Jinja2提供的常见过滤器

过滤器名 说明
safe 渲染值时不转义
capitalize 把值的首字母转换成大写,其他字母转换成小写
lower 把值转换成小写形式
upper 把值转换成大写形式
title 把值中每个单词的首字母都转换成大写
trim 把值的首尾空格去掉
striptags 渲染之前把值中所有的HTML标签都删掉

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

千万别在不可信的值上使用safe过滤器,例如用户在表单中输入的文本。

Jinja2提供了多种控制结构,可用来改变模板的渲染流程。
- 使用条件控制语句。

1
2
3
4
5
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
- for循环,常见需求是在模板中渲染一组元素。
1
2
3
4
5
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
  • Jinja2还支持宏。宏类似于Python代码中的函数。
    1
    2
    3
    4
    5
    6
    7
    8
    {% macro render_comment(comment) %}
    <li>{{ comment }}</li>
    {% endmacro %}
    <ul>
    {% for comment in comments %}
    {{ render_comment(comment) }}
    {% endfor %}
    </ul>
    为了重复使用宏,我们可以将其保存在单独的文件中,然后在需要使用的模板中导入:
    1
    2
    3
    4
    5
    6
    {% import 'macros.html' as macros %}
    <ul>
    {% for comment in comments %}
    {{ macros.render_comment(comment) }}
    {% endfor %}
    </ul>
    需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复:
    1
    {% include 'common.html' %}

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

1
2
3
4
5
6
7
8
9
10
11
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>

block标签定义的元素可在衍生模板中修改。在本例中,我们定义了名为head、title和body的块。注意,title包含在head中。下面这个示例是基模板的衍生模板:

1
2
3
4
5
6
7
8
9
10
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}

extends指令声明这个模板衍生自base.html。在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容。

自定义错误页面

Flask允许程序使用基于模板的自定义错误页面。最常见的错误代码有两个:

  • 404,客户端请求未知页面或路由时显示;
  • 500,有未处理的异常时显示。
    为这两个错误代码指定自定义处理程序的方式如下所示:
    1
    2
    3
    4
    5
    6
    @app.errorhandler(404)
    def page_not_found(e):
    return render_template('404.html'), 404
    @app.errorhandler(500)
    def internal_server_error(e):
    return render_template('500.html'), 500

使用模板继承可以避免大量的体力劳动

链接与静态文件

任何具有多个路由的程序都需要可以连接不同页面的链接,在模板中直接编写简单路由的URL链接不难,但对于包含可变部分的动态路由,在模板中构建正确的URL就很困难。为了避免这些问题,Flask提供了url_for()辅助函数,它可以使用程序URL映射中保存的信息生成URL。url_for()函数最简单的用法是以视图函数名(或者app.add_url_route()定义路由时使用的端点名)作为参数,返回对应的URL。例如,在当前版本的hello.py程序中调用url_for(‘index’)得到的结果是/。调用url_for('index', _external=True)返回的则是绝对地址,在这个示例中是http://localhost:5000/。
使用url_for()生成动态地址时,将动态部分作为关键字参数传入。例如,url_for(‘user’, name=’john’, _external=True)的返回结果是http://localhost:5000/user/john。传入url_for()的关键字参数不仅限于动态路由中的参数。函数能将任何额外参数添加到查询字符串中。例如,`url_for(‘index’, page=2)`的返回结果是/?page=2。

Web程序不是仅由Python代码和模板组成。大多数程序还会使用静态文件,例如HTML代码中引用的图片、JavaScript源码文件和CSS。默认设置下,Flask在程序根目录中名为static的子目录中寻找静态文件。如果需要,可在static文件夹中使用子文件夹存放文件。例如:

1
2
3
4
5
6
7
{% block head %}
{{ super() }}
<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">
{% endblock %}

评论