模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask 使用了一个名为 Jinja2 的强大模板引擎
形式最简单的 Jinja2 模板就是一个包含响应文本的文件,例如:
<h1>Hello, {{ name }}!</h1>
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、运行程序,查看模版渲染效果
在模板中使用的{{ 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 提供的部分常用过滤器:
{{ my_html_content | safe }}
{{ my_string | capitalize }}
{{ my_string | lower }}
{{ my_string | upper }}
{{ my_string | title }}
{{ my_string | trim }}
safe 过滤器值得特别说明一下。默认情况下,出于安全考虑,Jinja2 会转义所有变量。例如,如果一个变量的值为 ‘<h1>Hello</h1>
’,Jinja2 会将其渲染成’<h1>Hello</h1>
',浏览器能显示这个 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 块,定义了页面的主体内容
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模版页面
任何具有多个路由的程序都需要可以连接不同页面的链接,例如导航条。
在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的依赖关系。如果重新定义路由,模板中的链接可能会失效。
为了避免这些问题,Flask 提供了 url_for()
辅助函数,它可以使用程序 URL 映射中保存的信息生成 URL。
url = url_for('index', name='john', _external=True)
上述代码的返回结果是,http://127.0.0.1:5000/index?name=john
Web 程序不是仅由 Python 代码和模板组成。大多数程序还会使用静态文件,例如HTML代码中引用的图片、JavaScript 源码文件和 CSS
1、在项目的static文件夹中上传icon网页图标文件
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图标设置成功