日課書

编程100小时挑战

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

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

Step 3:创建视图函数

用户登录首页时会进行判断,如果是登录用户则显示,用户关注的时间线,如果没登录则显示公共的时间线。

在首页会有登录登出的选项,这个具体的选项会根据目前用户状态进行判断。如果是未登录则点击进入登录页面,登录成功后返回用户关注的时间线。如果用户已登录,则显示登出,登出后返回公共时间线。

如果是未登录状态,首页还会有注册选项。点击进入注册页面,注册成功后跳转至登录页面。

其次登录用户还可以进入特定的其他用户界面,以浏览某用户的全部微博。在用户的个人界面,可以选择关注或者取消关注某用户。并且可以查看该用户的关注列表。

  • 在处理每个请求前,判断用户是否已登录
    1
    2
    3
    4
    5
    6
    @app.before_request
    def before_request():
    g.user = None
    if 'user_id' in session:
    g.user = query_db('select * from users where user_id = ?',
    [session['user_id']], one=True)

通过分析,我们得知在整个网站中需要用到一下链接和对应的视图函数:

  • 首页。

当用户进入首页时判断用户是否登录,如果登录则显示个人的时间线,以显示自己和关注人的消息。否则重定向到公开时间线。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import session, render_template, redirect, url_for

PER_PAGE = 20

@app.route('/')
def timeline():
if not g.user:
return redirect(url_for('public_timeline'))
query = '''
SELECT messages.*, users.* FROM messages, users
WHERE messages.user_id = users.user_id AND (
users.user_id = ? OR
users.user_id IN (SELECT followed_id FROM follows
WHERE follower_id = ?))
ORDER BY messages.pub_time DESC LIMIT ?'''

messages = query_db(query, [session['user_id'], session['user_id'], PER_PAGE])
return render_template('timeline.html', messages=messages)
  • 公共主页

公共时间线显示最近发布的若干条信息。

1
2
3
4
5
6
7
8
@app.route('/public')
def public_timeline():
query = '''
SELECT messages.*, users.* FROM messages, users
WHERE messages.user_id = users.user_id
ORDER BY messages.pub_time DESC LIMIT ?'''

messages = query_db(query, [PER_PAGE])
return render_template('timeline.html', messages=messages)
  • 用户页

用户页用以显示单个用户发布的所有消息。

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

@app.route('/<username>')
def user_timeline(username):
profile_user = query_db('SELECT * FROM user WHERE user_name = ?',
[username], one=True)
if profile_user is None:
abort(404)
followed = False
if g.user:
followed = query_db('''SELECT 1 FROM follows WHERE
follows.follower_id = ? AND follows.followed_id = ?''',

[session['user_id'], profile_user['user_id']],
one=True) is not None
query = '''
SELECT messages.*, users.* FROM messages, users
WHERE users.user_id = message.user_id AND users.user_id = ?
ORDER BY messages.pub_time DESC LIMIT ?'''

messages = query_db(query, [profile_user[user_id], PER_PAGE])
return render_template('timeline.html', messages=messages,
followed=followed, profile_user=profile_user)
  • 关注

关注用户,就是在关注表中添加一条记录,关注人为当前登录用户,被关注者为浏览的用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import flash

@app.route('/<username>/follow')
def follow(username):
if not g.user:
abort(401)
followed_id = get_user_id(username)
if followed_id is None:
abort(404)
db = get_db()
db.execute('''INSERT INTO follows (follower_id, followed_id)
VALUES (?, ?)''', [session['user_id'], followed_id])

db.commit()
flash('Your are now following "%s".' % username)
return redirect(url_for('user_timeline', username=username))
  • 取消关注
1
2
3
4
5
6
7
8
9
10
11
12
13
@app.route('/<username>/unfollow')
def unfollow(username):
if not g.user:
abort(401)
followed_id = get_user_id(username)
if followed_id is None:
abort(404)
db = get_db()
db.execute('DELETE FROM follows WHERE follower_id=? AND followed_id=?',
[session['user_id'], followed_id])
db.commit()
flash('You are no longer following "%s".' % username)
return redirect(url_for('user_timeline', username=username))
  • 发布消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time
from flask import request

@app.route('/add_message', methods=['POST'])
def add_message():
if not g.user:
abort(401)
if request.form['text']:
db = get_db()
db.execute('''INSERT INTO messages (user_id, text, pub_time)
VALUES (?, ?, ?)''', [session['user_id'], request.form['text'],

int(time.time())])
db.commit()
flash('Your message was recorded.')
return redirect(url_for('timeline'))
  • 注册

注册时,首先要检查用户的提交的信息是否完整,其次检查是否重名。为了安全起见,我们用werkzeug库提供的函数,对密码进行哈希处理,避免在数据库中明文存储密码。

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
from werkzeug import generate_password_hash

@app.route('/register', methods=['GET', 'POST'])
def register():
if g.user:
return redirect(url_for('timeline'))
error = None
if request.method == 'POST':
if not request.form['username']:
error = 'You have to enter a username'
elif not request.form['email'] or \
'@' not in request.form['email']:
error = 'You have to enter a valid emial address'
elif not request.form['password']:
error = 'You have to enter a password'
elif request.form['password'] != request.form['password2']:
error = 'The two password do not match'
elif get_user_id(request.form['username']) is not None:
error = 'The username is already taken'
else:
db = get_db()
db.execute('''INSERT INTO users (user_name, email, pw_hash) VALUES
(?, ?, ?)''', [request.form['username'], request.form['email'], generate_password_hash(request.form['password'])])

db.commit()
flash('You were successfully registered and can login now')
return redirect(url_for('login'))
if error:
flash(error)
return render_template('register.html')
  • 登录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from werkzeug import check_password_hash

@app.route('/login', methods=['GET', 'POST'])
def login():
if g.user:
return redirect(url_for('timeline'))
error = None
if request.method == 'POST':
user = query_db('''SELECT * FROM users WHERE user_name=?''',
[request.form['username']], one=True)
if user is None:
error = 'Invalid username'
elif not check_password_hash(user['pw_hash'], request.form['password']):
error = 'Invalid password'
else:
flash('You were logged in.')
session['user_id'] = user['user_id']
return redirect(url_for('timeline'))
if error:
flash(error)
return render_template('login.html')
  • 登出
1
2
3
4
5
@app.route('/logout')
def logout():
flash('You were logged out')
session.pop('user_id', None)
return redirect(url_for('public_timeline'))
  • 查看关注列表

通过关注列表,用户可以获取与自己有关的关注信息,包括自己关注的人,和关注自己的人。

1
2
3
4
5
6
7
8
9
@app.route('/follow_list')
def follow_list():
if not g.user:
abort(401)
followed = query_db('SELECT * FROM follows WHERE follower_id=?',
[session['user_id']])
follower = query_db('SELECT * FROM follows WHERE followed_id=?',
[session['user_id']])
return render_template('follow_list.html', followed=followed, follower=follower)

待续


Step 4:制作模板

Step 5:测试程序

Step 6: 部署程序