步骤6:视图函数

Now that the database connections are working, you can start writing the view functions. 你一共需要写四个:

显示条目

This view shows all the entries stored in the database. 它绑定在应用的根地址,并从数据库查询出文章的标题和正文。 The one with the highest id (the newest entry) will be on top. 从光标返回的行看有点像词典因为我们正在使用sqlite3.Row行工厂函数。

视图函数会将条目作为字典传递给show_entries.html模板,并返回渲染结果:

@app.route('/')
def show_entries():
    db = get_db()
    cur = db.execute('select title, text from entries order by id desc')
    entries = cur.fetchall()
    return render_template('show_entries.html', entries=entries)

添加新条目

这个视图允许已登入的用户添加新条目。它并只响应POST请求;实际的表单显示在show_entries页。If everything worked out well, it will flash() an information message to the next request and redirect back to the show_entries page:

@app.route('/add', methods=['POST'])
def add_entry():
    if not session.get('logged_in'):
        abort(401)
    db = get_db()
    db.execute('insert into entries (title, text) values (?, ?)',
                 [request.form['title'], request.form['text']])
    db.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))

注意,这个视图检查用户是否登入(即,如果logged_in键在会话中存在,并且为True)。

Security Note

Be sure to use question marks when building SQL statements, as done in the example above. 否则,当你使用格式化字符串构建 SQL 语句时,你的应用容易遭受 SQL 注入。 See Using SQLite 3 with Flask for more.

登入和登出

These functions are used to sign the user in and out. Login checks the username and password against the ones from the configuration and sets the logged_in key for the session. 如果用户成功登入,那么这个键值会被设为True,并从定向回show_entries页。In addition, a message is flashed that informs the user that he or she was logged in successfully. If an error occurred, the template is notified about that, and the user is asked again:

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != app.config['USERNAME']:
            error = 'Invalid username'
        elif request.form['password'] != app.config['PASSWORD']:
            error = 'Invalid password'
        else:
            session['logged_in'] = True
            flash('You were logged in')
            return redirect(url_for('show_entries'))
    return render_template('login.html', error=error)

logout函数,做相反的事情,从会话中删除这个键。我们这里使用了一个简洁的方法:如果你使用字典的pop()方法并传入第二个参数(默认), 这个方法会从字典中删除这个键,如果这个键不存在则什么都不做。This is helpful because now it is not necessary to check if the user was logged in.

@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    flash('You were logged out')
    return redirect(url_for('show_entries'))

安全提示

永远不要把密码以明文形式存储在生产系统中。为简单起见,本教程使用纯文本密码。如果你计划发布基于本教程的项目,密码应该在存储到数据库或文件之前散列和加盐

幸运的是,有Flask扩展用于哈希密码和验证密码的哈希值,因此添加此功能是相当简单的。也有许多可以用于哈希的一般 python 库。

你可以在这里找到推荐的一个Flask扩展列表。

继续步骤7:模板