模板的基本使用
渲染模板
在使用 PyCharm Professional 版创建完一个 Flask 项目后,默认会生成一个 templates 文件夹,如果没有修改模板查找路径,默认会在这个文件夹下寻找模板文件。模板文件可以是任意纯文本格式的文件,如 TXT、HTML、XML 等,但是为了让项目更规范,也为了与前端开发者更无缝地协作,一般都是用 HTML 文件来写模板代码。
如果读者用的是非 PyCharm Professional 版创建的 Flask 项目,则可以手动创建 templates 文件夹。 |
首先在 templates 文件夹下创建 index.html 文件,然后输入以下代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>这是首页</h1>
</body>
</html>
接下来在视图函数中使用 render_template 函数渲染 index.html 模板。在 app.py 中,将原来的 hello_world 视图函数修改为以下代码。
from flask import Flask,render_template
...
@app.route('/')
def index():
return render_template("index.html")
render_template 默认会从当前项目的 templates 文件夹下寻找 index.html 文件,读取后进行解析,再渲染成 HTML 代码返回给浏览器。在浏览器中访问 http://127.0.0.1:5000 ,可以看到如图 4-1 所示的效果。

从图 4-1 中可以看到,“这是首页” 4 个字已经是一级标题了,原因是模板中给 “这是首页” 4 个字外面套了一个 h1 标签,至此我们就完成了一个最简单的模板渲染。
如果想修改模板文件的查找地址,可以在创建 app 时,给 Flask 类传递一个关键字参数 template_folder 指定具体路径,示例代码如下。
如此操作以后,Flask 在寻找模板文件时,就不再从当前项目下的 templates 文件夹寻找了,而是从 template_folder 指定的路径寻找。项目在 Debug 模式开启的前提下再访问 http://127.0.0.1:5000 ,会出现如图 4-2 所示的错误。

模板没有找到的原因是,在 template_folder 指定的文件夹下不存在一个叫作 index.html 的模板,如果想要解决此问题,只需要把 templates 文件夹下的 index.html 复制到 template_folder 指定的文件夹下即可。
渲染变量
HTML 文件中的有些数据是需要动态地从数据库中加载的,不能直接在 HTML 中写死。一般的做法是,在视图函数中把数据先提取好,然后使用 render_template 渲染模板时传给模板,模板再读取并渲染出来。下面新建一个 URL 与视图函数映射,示例代码如下。
@app.route("/variable")
def variable():
hobby = "游戏"
return render_template("variable.html", hobby=hobby)
以上代码中渲染了一个 variable.html 模板,这个模板文件的创建接下来会具体讲解。除模板名称外,还给 render_template 传递了一个 hobby 关键字参数,后续在模板中就可以使用这个变量了。
现在再在 templates 文件夹下创建一个 variable.html 模板文件(注意:要记得先删掉 template_folder 参数),然后输入以下代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>变量使用</title>
</head>
<body>
<h1>我的兴趣爱好是:{{ hobby }}</h1>
</body>
</html>
从以上代码中可以看到,把变量放到两对花括号中即可使用变量。项目运行起来后,在浏览器中访问 http://127.0.0.1:5000/variable ,效果如图 4-3 所示。

图4-3 中的文字 “游戏” 是从视图函数中通过 render_template 传过去的,并不是在 HTML 中写死的,所以变量的使用可以让同一个 HTML 模板渲染无数个不同的页面。
字典的键和对象的属性在模板中都可以通过点(.
)的形式访问。在 variable 这个视图函数中添加两个新的变量,分别是字典类型的 person,以及类对象类型的 user。示例代码如下。
class User:
def __init__(self, username, email):
self.username = username
self.email = email
@app.route("/variable")
def variable():
hobby = "游戏"
person = {
"name": "张三",
"age": 18
}
user = User("李四", "xx@qq.com")
return render_template("variable.html", hobby=hobby, person=person, user=user)
接下来,再在 variable.html 模板中通过点(.
)的形式访问 person 的键和 user 属性。代码如下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>变量使用</title>
</head>
<body>
<h1>我的兴趣爱好是:{{ hobby }}</h1>
<p>person的姓名是:{{ person.name }},person的年龄是:{{ person.age }}</p>
<p>user的用户名是:{{ user.username }},user的邮箱是:{{ user.email }}</p>
</body>
</html>
在浏览器中重新访问 http://127.0.0.1:5000/variable ,效果如图 4-4 所示。
字典键和对象的属性也都可以通过中括号的形式获取,如以下代码实际上是等价的。
{{ user.name }}
{{ user["name"] }}
读者可以自行修改 variable.html 中获取键和属性值的方式,最终效果是一样的。用点和中括号的形式访问,虽然效果一样,但是也存在以下不同。

(1)在模板中有一个变量的使用方式为 foo.bar,那么在 Jinja2 中则按以下方式进行访问。
-
通过
getattr(foo, 'bar')
访问,先访问这个对象的属性。 -
如果没有找到,就通过
foo.__getitem__("bar")
方式访问,即访问这个对象的键。 -
如果以上两种方式都没有找到,返回一个
undefined
对象。
(2)在模板中有一个变量的使用方式为 foo["bar"],那么在 Jinja2 中则按以下方式进行访问。
-
通过
foo.__getitem__("bar")
方式访问,即先访问这个对象的键。 -
如果没有找到,就通过
getattr(foo, "bar")
方式访问,即访问这个对象的属性。 -
如果以上都没找到,则返回一个
undefined
对象。
以上案例中,传递了 3 个变量到模板中,在变量比较多的情况,首先可以把所有的变量存放到字典中,然后在给 render_template 传递参数时使用 **
语法,将字典变成关键字参数,以上的 variable 视图函数代码可以改写为以下形式。
@app.route("/variable")
def variable():
hobby = "游戏"
person = {
"name": "张三",
"age": 18
}
user = User("李四", "xx@qq.com")
context = {
"hobby": hobby,
"person": person,
"user": user
}
return render_template("variable.html", **context)
以上代码的写法更加直观和简洁,在遇到需要传给模板的变量比较多的情况,都推荐使用这种方式。