上一节讲了如何安装:-python轻量框架--Flask(入门教程)
这一节讲Flask模板。
1.回顾
上一节目录:
venv\
<virtual environment files>
app\
static\
templates\
__init__.py
views.py
tmp\
run.py
你可以执行 run.py
来运行应用程序,接着在你的网页浏览器上打开 http://localhost:5000 网址。
在python中生成HTML并不好玩,实际上是相当繁琐的,因为你必须自行做好 HTML 转义以保持应用程序的安全。由于这个原因,Flask 自动为你配置好 Jinja2
模版。我们将会在这一章中介绍一些模板基本概念以及基本用法。
2.为什么我们需要模板
让我们来考虑下我们该如何扩充我们的应用程序——小微博。
修改之前的views.py程序,输出欢迎用户的标题,修改后如下:
from app import app
@app.route('/')
@app.route('/index')
def index():
user = { 'nickname': 'JayMo' } # fake user
return '''
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Hello, ''' + user['nickname'] + '''</h1>
</body>
</html>
'''
运行看看网页浏览器上的显示情况。如图:
我们暂时还不支持用户,所以暂时使用占位符的用户对象,有时也被称为假冒或模仿的对象。这样让我们可以集中关注应用程序的某一方面,而不用花心思在暂未完成的部分上。
看到上面的代码,是不是觉得很麻烦。特别是如果我们需要返回一个含有大量动态内容的大型以及复杂的 HTML 页面的话,代码将会有多么复杂啊!如果你需要改变你的网站布局,在一个大的应用程序,该应用程序有几十个视图,每一个直接返回HTML?这显然不是一个可扩展的选择。
3.模板的生成
如果你能够保持你的应用程序与网页的布局或者界面逻辑上是分开的,这样不是显得更加容易组织?
模板可以帮助实现这种分离。
3.1 让我们编写第一个我们的模板(文件 app/templates/index.html):
<html>
<head>
<title>{{title}} - microblog</title>
</head>
<body>
<h1>Hello, {{user.nickname}}!</h1>
</body>
</html>
正如你在上面看到,我们只是写了一个大部分标准的HTML页面,唯一的区别是有一些动态内容的在 {{ … }} 中。
3.2 现在看看怎样在我们的视图函数(文件 app/views.py)中使用这些模板:
from flask import render_template
from app import app
@app.route('/')
@app.route('/index')
def index():
user = { 'nickname': 'Miguel' } # fake user
return render_template("index.html",
title = 'Home',
user = user)
3.3 运行刷新浏览器。
解释:
为了渲染模板,我们必须从 Flask 框架中导入一个名为 render_template 的新函数。此函数需要传入模板名以及一些模板变量列表,返回一个所有变量被替换的渲染的模板。
在内部,render_template 调用了 Jinja2 模板引擎,Jinja2 模板引擎是 Flask 框架的一部分。Jinja2 会把模板参数提供的相应的值替换了 {{…}} 块。为了渲染模板,我们必须从 Flask 框架中导入一个名为 render_template 的新函数。此函数需要传入模板名以及一些模板变量列表,返回一个所有变量被替换的渲染的模板。
在内部,render_template 调用了
Jinja2 模板引擎,Jinja2 模板引擎是 Flask 框架的一部分。Jinja2 会把模板参数提供的相应的值替换了 {{…}} 块。
4. 模板中控制语句
Jinja2 模板同样支持控制语句,像在 {%…%} 块中。让我们在我们的模板中添加一个 if 声明(文件 app/templates/index.html):
<html>
<head>
{% if title %}
<title>{{title}} - microblog</title>
{% else %}
<title>Welcome to microblog</title>
{% endif %}
</head>
<body>
<h1>Hello, {{user.nickname}}!</h1>
</body>
</html>
现在我们的模板变得更加智能了。如果视图函数忘记输入页面标题的参数,不会触发异常反而会出现我们自己提供的标题。放心地去掉视图函数中 render_template 的调用中的 title 参数,看看 if 语句是如何工作的!
5.模板中的循环语句
在我们 microblog 应用程序中,登录的用户想要在首页展示他的或者她的联系人列表中用户最近的文章,因此让我们看看如何才能做到。
5.1 首先我们先创建一些用户以及他们的文章用来展示(文件 app/views.py):
def index():
user = { 'nickname': 'Miguel' } # fake user
posts = [ # fake array of posts
{
'author': { 'nickname': 'John' },
'body': 'Beautiful day in Portland!'
},
{
'author': { 'nickname': 'Susan' },
'body': 'The Avengers movie was so cool!'
}
]
return render_template("index.html",
title = 'Home',
user = user,
posts = posts)
在模板这一方面,我们必须解决一个新问题。列表中可能有许多元素,多少篇文章被展示将取决于视图函数。模板不会假设有多少文章,因此它必须准备渲染视图传送的文章数量。
5.2 因此让我们来看看怎么使用 for 来做到这一点(文件 app/templates/index.html):
<html>
<head>
{% if title %}
<title>{{title}} - microblog</title>
{% else %}
<title>microblog</title>
{% endif %}
</head>
<body>
<h1>Hi, {{user.nickname}}!</h1>
{% for post in posts %}
<p>{{post.author.nickname}} says: <b>{{post.body}}</b></p>
{% endfor %}
</body>
</html>
简单吧?试试吧,确保给予足够的文章列表。
6. 模板继承
在我们的 microblog 应用程序中,在页面的顶部需要一个导航栏。在导航栏里面有编辑账号,登出等等的链接,每个模板都需要有这个导航栏。
我们可以利用 Jinja2 的模板继承的特点,这允许我们把所有模板公共的部分移除出页面的布局,接着把它们放在一个基础模板中,所有使用它的模板可以导入该基础模板。
6.1 定义一个基础模板
该模板包含导航栏以及上面谈论的标题(文件 app/templates/base.html):
<html>
<head>
{% if title %}
<title>{{title}} - microblog</title>
{% else %}
<title>microblog</title>
{% endif %}
</head>
<body>
<div>Microblog: <a href="/index">Home</a></div>
<hr>
{% block content %}{% endblock %}
</body>
</html>
在这个模板中,我们使用 block
控制语句来定义派生模板可以插入的地方。块被赋予唯一的名字。
6.2 接着现在剩下的就是修改我们的 index.html 模板继承自 base.html
(文件 app/templates/index.html):
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{user.nickname}}!</h1>
{% for post in posts %}
<div><p>{{post.author.nickname}} says: <b>{{post.body}}</b></p></div>
{% endfor %}
{% endblock %}
在下一章中,我们将会讨论到表单。