日課書

编程100小时挑战

利用Flask创建一个mini微博(3)

利用Flask创建一个mini微博(1)
利用Flask创建一个mini微博(2)

Step 4:制作模板

使用Bootstrap

Bootstrap是一个HTML,css,JS框架,使用它可以让我们创建出样式整洁的网页。在添加模板的过程中,我们引入一个新的Flask扩展,Flaks-Bootstrap。这个扩展可以让Flask更简单的使用Bootstrap。

首先我们要安装一个名为Flask-Bootstrap的Flask扩展。

1
$ pip install Flask-Bootstrap

初始化Flask—Bootstrap:

1
2
3
4
# miniweibo.py
from flask.ext.bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)

在初始化后,我们就可以在程序中使用一个包含所有Bootstrap文件的基模板。利用Jinja2模板的继承机制,我们可以扩展一个有基本页面布局的基模板,其中可以引入Bootstrap元素。

接下来我们就利用Bootstrap就来定义下我们miniWeibo的基本页面布局。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!-- templates/layout.html -->
{% extends "bootstrap/base.html" %}

{% block title %}MiniWeibo{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="botton" class="navbar-toggle"
data-toggle="collapse" data-target=".navbar-collapse">

<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">MiniWeibo</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
{% if g.user %}
<li><a href=url_for('logout')>Sign out</a></li>
{% else %}
<li><a href=url_for('login')>Sign in</a></li>
<li><a href=url_for('register')>Register</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
{% endblock %}

{% block content %}
<div class="container col-xs-12 col-md-8 col-md-offset-2container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}

用户在进行某项操作后,正常的交互流程应该及时给用户以反馈。Flask使用flash()消息来实现这个功能。flash()函数并不能直接把消息显示出来,需要使用模板进行渲染。最好在基模板中渲染flash消息,这样所有页面都能使用这些消息。Flask把get_flashed_messages()函数开放给模板,用来获取并渲染消息。对模板进行相应的修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- templates/layout.html -->
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ message }}
</div>
{% endfor %}

{% block page_content %}{% endblock %}
</div>
{% endblock %}

自定义错误页面

如果你在浏览器中输入不可用的链接,会显示一个状态码为404的错误页面,Flask自动生成的页面比较简陋,样式也和我们自己定义的页面不一致。Flask也允许程序使用基于模板的自定义错误页面。最常见的错误代码有:404和401。为这两个错误代码指定自定义处理的方式如下:

1
2
3
4
5
6
7
8
# miniweibo.py
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404

@app.errorhandler(401)
def unauthorized(e):
return render_template('401.html'), 401

通过继承布局来创建自定义错误页面

1
2
3
4
5
6
7
8
9
10
<!-- templates/404.html -->
{% extends "layout.html" %}

{% block title %}MiniWeibo - Page Not Found{% endblock %}

{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
</div>
{% endblock %}

模板

设计

用户注册页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- templates/register.html -->
{% extends "layout.html" %}

{% block title %}MiniWeibo - Register{% endblock %}

{% block page_content %}
<form method="POST">
<div class="form-group">
<label>User name</label>
<input type="text" class="form-control" name="username" placeholder="User name">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" name="email" placeholder="Email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
<div class="form-group">
<label>Password confirm</label>
<input type="password" class="form-control" name="password2" placeholder="Password confirm">
</div>
<button type="submit" class="btn btn-default">Submit</botton>
</form>
{% endblock %}

登录页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- tmplates/login.html -->
{% extends "layout.html" %}

{% block title %}MiniWeibo - Sign in{% endblock %}

{% block page_content %}
<form method="POST">
<div class="form-group">
<label>User name</label>
<input type="text" class="form-control" name="username" placeholder="User name">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-default">Submit</botton>
</form>
{% endblock %}

时间线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!-- templates/timeline.html -->
{% extends "layout.html" %}

{% block title %}
{% if request.endpoint == 'public_timeline' %}
Public timeline
{% elif request.endpoint == 'user_timeline' %}
{{ profile_user.user_name }}'s Timeline
{% else %}
My Timeline
{% endif %}
{% endblock %}

{% block page_content %}
<h2>{{ self.title() }}</h2>
{% if g.user %}
{% if request.endpoint == 'user_timeline' %}
<div class="followstatus">
{% if g.user.user_id == profile_user.user_id %}
This is you!
{% elif followed %}
You are currently following this user.
<a class="unfollow" href="{{ url_for('unfollow',
username=profile_user.user_name) }}">
Unfollow</a>

{% else %}
You are not yet following this user.
<a class="follow" href="{{ url_for('follow',
username=profile_user.user_name) }}">
Follow</a>

{% endif %}
</div>
{% elif request.endpoint == 'timeline' %}
<div class="postbox">
<form action="{{ url_for('add_message') }}" method="POST">
<div class="form-group">
<label>What's in your mind?</label>
<textarea rows="3" class="form-control" name="text">
</textarea>
</div>
<button type="submit" class="btn btn-default">post</botton>
</form>
</div>
{% endif %}
{% endif %}
<ul class="posts">
{% for message in messages %}
<li class="post">
<div class="post-author"><a href="{{ url_for('user_timeline', username=message.user_name) }}">{{ message.user_name }}</a></div>
<div class="post-body">{{ message.text }}</div>
</li>
{% else %}
<li><em>There's no message so far.</em>
{% endfor %}
</ul>
{% endblock %}

在布局模板中添加Bootstrap以外的自定义样式:

1
2
3
4
5
<!-- templates/layout.html -->
{% block head %}
{{ super() }}
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='style.css') }}">
{% endblock %}

定义样式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.posts {
list-style-type: none;
padding: 0px;
margin: 16px 0px 0px 0px;
border-top: 1px solid #e0e0e0;
}
.post {
padding: 8px;
border-bottom: 1px solid #e0e0e0;
}
.post-author {
font-weight: bold;
}
.post-body {
padding: 10px 10px 10px 10px;
}

待续


Step 5:测试程序

Step 6: 部署程序