在新版本的hello.py
中,index()
视图函数渲染表单并接收其数据。示例4-4展现更新后的index()
视图函数。html
示例4-4. hello.py:路由方法git
@app.route('/', methods=['GET', 'POST']) def index(): name = None form = NameForm() if form.validate_on_submit(): name = form.name.data form.name.data = '' return render_template('index.html', form=form, name=name)
methods
参数被添加到app.route
装饰器中,目的是让Flask注册视图函数为GET
和POST
请求处理程序到URL映射中。若methods
参数未给出,视图函数将只注册为GET
请求。github
添加POST
到方法列表中是有必要的,由于表单提交使用POST
请求操做会更方便。使用GET
请求提交表单也行,只是GET
请求没有body
部分,数据是追加到URL上做为返回字符串且能够在浏览器的地址栏中看到。因为这个和其余一些缘由,表单提交一般使用POST
请求。web
局部变量name
用于保存从表单中接收到的名字,初始化时变量为None
。视图函数建立一个NameForm
实例来表示一个表单。表单的validate_on_submit()
方法会在表单被提交且数据经过了全部验证的时候返回True
。其余状况下validate_on_submit()
返回False
。该方法的返回值有效的决定了表单是须要渲染仍是其余处理。数据库
当用户第一次访问应用程序,服务器会收到一个没有表单数据的GET
请求,这个时候validate_on_submit()
会返回False
。if
语句中的代码将被略过直接进行渲染模板处理,这个时候render_template()
函数将获取表单对象和已经被设置为None
的name
变量做为参数。用户则能够在浏览器上看到表单的显示。flask
当用户提交表单,服务器会收到一个带有数据的POST
请求。validate_on_submit()
调用Required()
验证程序验证相应的表单域。若是name
不为空,验证程序接收它同时validate_on_submit()
返回True
。如今用户输入的名字已是做为表单域可访问的数据属性。在if
语句中,这个名字被赋值给局部变量name
且表单域的数据属性经过赋值为空字符串而被清除。调用最后一行的render_template()
来渲染模板,可是此次name
参数包含了来自表单的名字,因此能够看到一个个性化的打招呼页面。浏览器
建议:若是你有克隆在GitHub上的应用程序,你如今能够运行
git checkout 4a
来切换到这个版本的应用程序。服务器
图像4-1展现用户初次进入网站在浏览器窗口看到的表单是怎样的。当用户提交名字,应用程序收到一个个性化的打招呼响应。下面的表单仍然出现,因此只要愿意用户能够提交一个新的名字。图像4-2展现用户输入名字后的状态。cookie
图像4-1. Flask-WTF的web表单session
若是用户提交一个空名字的表单,Required()
验证程序捕捉到错误,就像图像4-3那样。注意这些功能都是自动提供的。这是一个很好的例子,精心设计的Flask-WTF和Flask-Bootstrap扩展能让您的应用程序更强大。
图像4-2. 提交后的web表单
图像4-3. 验证错误后的web表单
上个版本的hello.py
有个问题。若是你输入你的名字并提交它,而后单击浏览器中刷新按钮,你将获得一个警告要求再次确认以前提交的表单。由于请求刷新页面的时候浏览器重复了上一次发送的请求。当上一次发送的是一个带有表单数据的POST
请求,刷新页面会致使重复的表单提交,事实上这些并非咱们想看到的。
许多用户不能理解来自浏览器的这些警告。出于这个缘由,对web应用程序来讲,一种不错的方法是永远不将POST
请求做为浏览器最后发送的请求。
这个方法可使用redirect响应POST
请求来代替常规的响应来实现。重定向是一个特殊类型的响应,使用URL来代替HTML代码字符串。当浏览器收到这个响应,它就会给重定向URL发出一个GET请求,而后显示页面。页面也许须要几毫秒的时间来加载,由于须要发送第二个请求给服务器,除此以外用户不会看到任何不一样。如今最后一次请求为GET
,因此刷新会像预期的那样。这个方法被称为Post/Redirect/Get模式。
可是这个方法带来了第二个问题。当应用程序处理POST
请求,须要访问用户输入并保存在form.name.data
中的名字,可是一旦该请求结束表单数据就会丢失。由于POST
请求是经过重定向来处理,应用程序须要存储名字,以便重定向后的请求能够获得它并使用它来建立真实的响应。
应用程序能够“记住”一些变量从一个请求到另外一个请求经过将变量保存到用户会话中,对于每个链接过来的客户端它都是一个私有存储区域。做为一个与请求上下文关联的变量之一,用户会话已经在第二章中介绍过了。它被称为会话并能够像Python标准字典那样访问。
注:默认状况下,用户会话被存放于客户端的cookies,使用配置的
SECRET_KEY
来加密签名。任何篡改cookie内容将会使签名无效,从而使会话失效。
示例4-5展现实现重定向和用户会话的index()
视图函数。
示例4-5. hello.py:重定向和用户会话
from flask import Flask, render_template, session, redirect, url_for @app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))
在上一个版本中,局部变量name
用于保存用户在表单中输入的姓名。这个变量位于用户会话中的session['name']
中,所以能够保存很长时间。
如今请求来自表单的合法数据都会以redirect()
调用来结束,生成HTTP重定向响应。redirect()
函数把URL做为重定向的参数。这个例子中使用的重定向URL是一个根URL,因此响应能够写成redirect('/')
这样简洁,可是咱们一般使用Flask的URL生成器函数url_for()
来代替。咱们鼓励使用url_for()
函数来生成URLs,由于该函数使用URL映射来生成URLs,因此生成的URLs保证与定义的路由兼容,而且使用这个函数任何路由名发生变化都会自动变得有效,路由功能不受影响。
url_for()
惟一必须的参数就是endpoint名,也是每一个路由的内部名。默认状况下,路由的endpoint是一个附加到视图函数的名称。在这个示例中,处理根URL的视图函数为index()
,因此给url_for()
的名称为index。
最后一个改动是在render_template()
函数中,使用session.get('name')
从会话中获取name
参数。和使用普通字典同样,使用get()
去请求字典key来避免发生找不到key异常,由于对于没有的keyget()
返回默认值None
。
建议:若是你有克隆在GitHub上的应用程序,你如今能够运行
git checkout 4b
来切换到这个版本的应用程序。
这个版本的应用程序,你能够在你的浏览器中刷新页面看到你预期的行为。
有时候在请求完成后给用户一个提示消息是很是有用的。能够是一个确认消息、警告消息或错误消息。典型的示例就是当你在网站提交登陆表单出现错误的时候服务器响应渲染登陆表单并伴随一条消息,告知你的用户名或密码无效。
做为核心特性Flask具备这样的功能。示例4-6展现如何使用flash()
函数来实现这一目的。
示例4-6. hello.py:消息提示
from flask import Flask, render_template, session, redirect, url_for, flash @app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): old_name = session.get('name') if old_name is not None and old_name != form.name.data: flash('Looks like you have changed your name!') session['name'] = form.name.data form.name.data = '' return redirect(url_for('index')) return render_template('index.html', form = form, name = session.get('name'))
在这个示例中,每次提交一个名字都会和用户会话中保存的名字进行比较。若是两个名字不同,flash()
函数会被调用,消息会在下一次发回客户端的响应中显示。
调用flash()
还不能获取并显示消息;应用程序使用的模板须要渲染这些消息。渲染消息最好的地方是在基础模板中,由于这可使得全部页面均可以使用这些消息。Flask提供get_flashed_messages()
函数给模板去接收消息并渲染它们,就像4-7展现的那样。
示例4-7. templates/base.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">×</button> {{ message }} </div> {% endfor %} {% block page_content %}{% endblock %} </div> {% endblock %}
在这个示例中,使用Bootstrap的警告CSS样式作警告消息渲染(展现在图像4-4中就是之一)。
图像4-4. 消息提示
这里须要使用循环由于可能会有多个消息排队显示,在前面的请求周期中每次都会调用flash()
。
从get_flashed_messages()
中检索到的消息在下次调用这个函数时是不会返回的。因此消息只显示一次而后丢弃。
建议:若是你有克隆在GitHub上的应用程序,你如今能够运行
git checkout 4c
来切换到这个版本的应用程序。
可以接收用户经过web表单发送的数据是大多数应用程序的基本功能,一样将数据到永久存储到媒介上也是必须的。下一章的主题是Flask和数据库的使用。