Flask开发Day2-模板页面

前言

在上一篇 Flask开发Day1-Hello world中,我们已经创建好了一个Flask应用,接下来,我们就会针对他进行功能的添加,实现出一个中小型项目的web应用。


动态用户显示

这个功能想要实现的是:根据不同用户显示出不同的欢迎界面

假设我们现在需要有一个欢迎用户的标题。虽然目前的应用程序还没有实现用户概念(需要与数据库打交道),但这不妨碍我使用一个Python字典来模拟一个用户。

1
user = {'username': 'Tom'}

代码编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from app import app


@app.route('/')
@app.route('/index')
def index():
user = {username:'Tom'}
return '''
<html>
<head>
<title>My home </title>
</head>
<body>

<h1>Hello, ''' + user['username'] + ''' !</h1>

</body>

</html>
'''
  • 注意,要在html 代码中嵌入其他内容,需要使用三引号进行包裹。

页面效果:


那么问题来了,功能的确是实现了,但是以后网页的维护怎么办? 我是指,当以后网页的用户变多了,我们总不可能在一张网页里写出所有用户的信息吧?而且如果哪天我决定更改这个应用的布局,那就不得不更新每个视图函数的HTML字符串。显然,随着应用的扩张,这种“写死”的方式完全不可行。


模板的实现

模板有助于实现页面展现和业务逻辑之间的分离。脚本这块,负责逻辑的实现,而页面渲染的内容,交个html文件,这样就实现了前后端分离操作。

一张模板就相当于一个函数,我们可以不断调用它,从而实现渲染多个页面的效果,减轻了代码的重复性,也便于后期的修改(更改一处,处处改变)。

在Flask中,模板被编写为单独的文件,存储在应用程序包内的templates文件夹中。 在确定你在microblog目录后,创建一个存储模板的目录:

1
(venv) $ mkdir app/templates

在下面可以看到你的第一个模板,它的功能与上面的index()视图函数返回的HTML页面相似。 把这个文件写在app/templates/index.html中:

1
2
3
4
5
6
7
8
<html>
<head>
<title>{{ title }} - Microblog</title>
</head>
<body>
<h1>Hello, {{ user.username }}!</h1>
</body>
</html>
  • 双花括号里面包含的内容是动态获取的,通过这种形式,我们可以获取到函数传入的参数。

渲染模板

网页渲染转移到HTML模板之后,视图脚本(routes.py)就能被简化:

1
2
3
4
5
6
7
8
from flask import render_template
from app import app

@app.route('/')
@app.route('/index')
def index():
user = {'username': 'Miguel'}
return render_template('index.html', title='Home', user=user)
  • 将模板转换为完整的HTML页面的操作称为渲染。 我们需要从Flask框架中导入一个名为render_template()的函数。
  • render_template()函数调用Flask框架原生依赖的Jinja2模板引擎。它需要传入渲染的页面,还有变量参数列表(会替换模板中双花括号里面的代码块)
  • 对比起之前return的一大串html代码,这样是不是更简洁呢? 更重要的是,这个模板是可以多次使用的

jinja2

在渲染过程中使用实际值替换占位符,只是Jinja2在模板文件中支持的诸多强大操作之一。

条件判断:

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
{% if title %}
<title>{{ title }} - Microblog</title>
{% else %}
<title>Welcome to Microblog!</title>
{% endif %}
</head>
<body>
<h1>Hello, {{ user.username }}!</h1>
</body>
</html>
  • 以上通过条件判断书写了两种情况的 title 显示(开始有了动态的感觉)
  • 在jinja2中,通过特定格式传入控制语句,其他的还有 for循环、过滤器、分隔符等等,其方法格式在官网上都有,有兴趣的可以去官网学习:http://docs.jinkan.org/docs/flask/

模板继承

我们可能在平常的网页中可能会看到这么个情况:例如豆瓣评分,页面的框架大多相同,变化的只是其中呈现的内容,那么框架相同则意味着相同的代码,我们有没有一种方法,使得模板中也可以互相共用代码?

Jinja2有一个模板继承特性,专门解决这个问题。从本质上来讲,就是将所有模板中相同的部分转移到一个基础模板中,然后再从它继承过来。


例如,我们现在编写一个base.html基础文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
{% if title %}
<title>{{ title }} - Microblog</title>
{% else %}
<title>Welcome to Microblog</title>
{% endif %}
</head>
<body>
<div>Microblog: <a href="/index">Home</a></div>

<hr>
{% block content %}{% endblock %}
</body>
</html>
  • 这里比较陌生的代码可能就是那个block关键字了。在jinja2中 block被赋予一个唯一的名称,派生的模板可以在提供其内容时进行引用。(就像HTML中link标签用来引入css文件一样)
  • block content 是一种固定写法,它让Jinja2知道如何将这模板合并成在一起。

有了基础文件之后,我们就可以修改index.html,在其中渲染base.html文件

1
2
3
4
5
6
{% extends "base.html" %}

{% block content %}
<h1>Hi, {{ user.username }}!</h1>

{% endblock %}
  • extends语句用来建立了两个模板之间的继承关系,后面跟着的渲染模板的文件
  • 这里block content里面出现的HTML代码就会当成附加内容,渲染到base.html里的block代码块中。

页面效果:



写在最后

需要注意的是,如果网页出现以下内容:

  • 可能就是你的代码书写错误,好好回想自己干了什么,然后去代码中看看
  • 大多数情况下,都是jinja2语法错误,在templates/xxx.html 各种文件中,它的注释有独特的写法(详见官方文档),如果使用HTML的<!-- -->就会出现以上报错(碰到的坑)