实际场景中的响应页面不会像我们做demo那样,返回一个很简单的HelloWorld。实际场景中,几千上万行的前端代码都有可能,这个时候把前端的代码放在试图函数中就显得很繁琐,并且很不好管理。Flask提供了相应页面的方案:构建模板。模板包含了前端的页面静态程序以及动态的变量,最终渲染成页面返回给用户。
Flask使用了Jinja2模板引擎,用来渲染页面。模板搜索路径默认在项目根目录下templates文件夹下,例:
<!-- templates/user.html -->
<h1>Hello, {{ name }}!</h1>
一、渲染模板
在上面的模板中出现了{{ name }}这样的代码,表明name是个变量,需要视图函数给出,然后由模板渲染,视图函数例:
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
Flask提供了render_template()函数将模板集成到了应用中,第一个参数是文件名,随后的参数都是键值对,键表示模板中的变量,值表示函数给出变量对应的值。
模板除了识别简单变量,还可以识别复杂变量:
<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>
变量的值可以通过过滤器修改,例首字母大写:
<!-- templates/user.html -->
<h1>Hello, {{ name|capitalize }}!</h1>
常用过滤器如下:
过滤器名 | 说明 |
---|---|
safe | 渲染时不转义 |
capitalize | 只首字母大写,其它字母小写 |
lower | 全部小写 |
upper | 全部大写 |
title | 单词首字母大写 |
strim | 首尾去空格 |
striptags | 去掉所有的HTML标签 |
safe过滤器比较特殊,jinja2默认会转移所有字符,包括前端代码,比如‘<h1>’会被渲染成‘<’,但有时候前端页面需要显示前端代码,就可以用safe。不能在表单提交中使用safe,防止被攻击。
二、控制结构
模板也有控制结构语句,条件判断、循环,甚至类似函数的宏以及引入和继承等。
条件判断:
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
循环:
<ul>
{% for comment in comments %}
<li>{{ comment }}</li>
{% endfor %}
</ul>
宏:
{% macro render_comment(comment) %}
<li>{{ comment }}</li>
{% endmacro %}
<ul>
{% for comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
为了重复使用宏,可以单独保存在一个文件,在需要的模板中导入:
{% import 'macros.html' as macros %}
<ul>
{% for comment in comments %}
{{ macros.render_comment(comment) }}
{% endfor %}
</ul>
引入重复使用模板代码:
{% include 'common.html' %}
继承:
<!-- templates/base.html -->
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
<!-- templates/other.html -->
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
继承的基模板使用区块定义,在继承模板中可以对这些块进行重写,如果需要使用基模板的相同内容可以使用super()。
三、模板中的链接
在模板中不能把链接写死,如果开发的路由变更,模板的链接将难以维护,为了避免这个问题,Flask提供了url_for()辅助函数,用来动态生成URL。
url_for()最简单的方式使用视图函数名作为参数,例:
url_for('index) # / 相对路径
url_for('index', _externl=True) # http://localhost:5000/ 绝对路径
url_for('user', name='john', _external=True) # http://localhost:5000/user/john 动态路由
url_for('user', name='john', page=2, version=1) # /user/john?page=2&version=1 动态路由+查询参数
四、静态文件
静态文件默认保存在根目录的static文件夹下,可以建立子文件夹。在模板中使用时如下,定义一个收藏夹图标:
{% block head %}
{{ supper() }}
<link rel="short 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 %}
注:本章写的比较笼统,主要因为有个认识就可以,学一遍就好了。因为实际应用不会使用模板,牵涉到传输、带宽、项目规划的问题。如果是开发软件的话,会使用前后端分离的方式。如果开发数据接口或者算法接口的话并不会用到这些内容,所以说如果不是必须,了解一下就好。我是后者,仅用来写接口。
参考资料:《Flask Web开发(第二版)》