视图方法用来对发送给应用的request做出回应。
blueprint创建
使用blueprint组织一组相关的views及其他代码。将这些views及代码注册到blueprint而不是直接注册到应用。之后,blueprint被注册到应用中。
下面是创建blueprint的例子:
flaskr/blueprint_sample.py
import functools
# blueprint、数据处理、路由和模板渲染的包
from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
# hash密码的生成和检验
from werkzeug.security import check_password_hash, generate_password_hash
from flaskr.db import get_db
# blueprint_name 是蓝图的名称
# target_directory 是视图函数(.py)文件存放的位置,如auth(用户的登录、注册、退出登录)、blog(博客的创建、修改、删除)等
bp = Blueprint('blueprint_name', __name__, url_prefix='/target_directory')
下面的代码把创建好的blueprint注册到factory function中:
flaskr/__init__.py
def create_app():
app = ...
# existing code omitted
from . import blueprint_sample
app.register_blueprint(blueprint_sample.bp)
return app
The first view:register
下面是register view,从中可以看到处理用户注册以及flask(广义上)处理输入信息的方法。
@bp.route('/register', methods=('GET', 'POST'))
def register():
if request.method == 'POST':
# 用request.form['<column_name>']从template获得表项
username = request.form['username']
password = request.form['password']
db = get_db()
# 在base.html的content section里输出error message
error = None
# 下面可以用作error check的参考代码
# 如果username为空;下同
if not username:
error = 'Username is required.'
elif not password:
error = 'Password is required.'
elif db.execute(
'SELECT id FROM user WHERE username = ?', (username,)
).fetchone() is not None:
error = 'User {} is already registered.'.format(username)
if error is None:
db.execute(
'INSERT INTO user (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
# 如果查询语句修改了数据,则需要紧接着加上commit语句
db.commit()
# 转到登录view
return redirect(url_for('auth.login'))
# flash存储了可以在模板中渲染的信息
flash(error)
# 当用户第一次来到register页或者信息有error的时候,直接返回register页
return render_template('auth/register.html')
fetchone() returns one row from the query. If the query returned no results, it returns None. Later, fetchall() is used, which returns a list of all results.
Login View
flaskr/auth.py
@bp.route('/login', methods=('GET', 'POST'))
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
user = db.execute(
'SELECT * FROM user WHERE username = ?', (username,)
).fetchone()
if user is None:
error = 'Incorrect username.'
elif not check_password_hash(user['password'], password):
error = 'Incorrect password.'
if error is None:
# 清空当前session
session.clear()
session['user_id'] = user['id']
# 重定向到合适的位置
return redirect(url_for('index'))
flash(error)
return render_template('auth/login.html')
bp.before_app_request() registers a function that runs before the view function, no matter what URL is requested. load_logged_in_user checks if a user id is stored in the session and gets that user’s data from the database, storing it on g.user, which lasts for the length of the request. If there is no user id, or if the id doesn’t exist, g.user will be None.
flaskr/auth.py
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM user WHERE id = ?', (user_id,)
).fetchone()
Logout
To log out, you need to remove the user id from the session. Then load_logged_in_user won’t load a user on subsequent requests.
flaskr/auth.py
@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
Require Authentication in Other Views
比较看不懂的地方。就先忽略啦。
Creating, editing, and deleting blog posts will require a user to be logged in. A decorator can be used to check this for each view it’s applied to.
flaskr/auth.py
def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))
return view(**kwargs)
return wrapped_view
This decorator returns a new view function that wraps the original view it’s applied to. The new function checks if a user is loaded and redirects to the login page otherwise. If a user is loaded the original view is called and continues normally. You’ll use this decorator when writing the blog views.
Endpoints and URLs
url_for()
中的内容要做变化。从login变为auth.login。