文档章节

(三)Flask初体验——web 表单

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:21
字数 3019
阅读 1
收藏 0

Flask 学习目录

(一)Flask初体验——Hello World
(二)Flask初体验——模板
(三)Flask初体验——web 表单


回顾

在上一章中,我们定义了一个简单的模板,使用占位符来虚拟了暂未实现的部分,比如用户以及文章等。

在本章我们将要讲述应用程序的特性之一——表单,所以我们来讨论如何使用 web 表单。

配置

为了能够处理 web 表单,我们将使用 Flask-WTF,该扩展封装了 WTForms 并且恰当地集成进 Flask 中。

许多 Flask 扩展需要大量的配置,因此我们将要在 microblog 文件夹的根目录下创建爱你一个配置文件以至于容易被编辑。文件名为 config.py ,文件内容为:

CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'

其中,CSRF_ENABLED 配置是为了激活跨站点请求伪造保护。在大多数情况下,你需要激活给配置使得你的应用程序更安全些。

SECRET_KEY 配置仅仅当 CSRF 激活的时候才需要,它是用来建立一个加密的令牌,用于验证一个表单。当你编写自己的应用程序的时候,请务必设置很难被猜测到密钥。

既然我们有了配置文件,我们需要告诉 Flask 去读取以及使用它。我们可以在 Flask 应用程序对象被创建后去做,文件位置是 app/__init__.py,方式如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask 

app = Flask(__name__)
app.config.from_object('config')
from app import views

用户登录表单

在 Flask-WTF 中,表单是表示成对象,Form 类的子类。一个表单子类简单地把表单的域定义成类的变量。

我们将要创建一个登录表单,用户用于认证系统。在我们应用程序中支持的登录机制不是标准的用户名/密码类型,我们将使用OpenID。OpenIDs 的好处就是认证是由 OpenID 的提供者完成的,因此我们不需要验证密码,这会让我们的网站对用户而言更加安全。

OpenID 登录仅仅需要一个字符串,被称为 OpenID。我们将在表单上提供一个 ‘remember me’ 的选择框,以至于用户可以选择在他们的网页浏览器上种植 cookie ,当他们再次访问的时候,浏览器能够记住他们的登录。

所以让我们编写第一个表单,文件位置是 app/forms.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask.ext.wtf import Form 
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired

class LoginForm(Form):
    openid = StringField('openid', validators = [DataRequired()])
    remember_me = BooleanField('remember_me', default = False)

这个类不言而明,我们导入 Form 类,接着导入两个我们需要的字段类,TextFieldBooleanField

DataRequired 验证器只是简单地检查相应域提交的数据是否是空。在 Flask-WTF 中有许多的验证器,我们在以后会看到它们。

表单模板

我们同样需要一个包含生成表单的 HTML 的模板。好消息是我们刚刚创建的 LoginForm 类知道如何呈现为 HTML 表单字段,所以我们只需啊哟集中精力在布局上。这里我们登录模板是 app/templates/login.html

<!-- extend from base layout -->
{% extends "base.html" %}

{% block content %}

<h1>Sign In</h1>
<form action = "" method="post" name="login">
    {{form.hidden_tag()}}
    <p>
        Please enter your OpenID: <br>
        {{form.openid(size = 80)}} <br>
    </p>
    <p>{{form.remember_me}} Remember Me</p>
    <p><input type="submit" value="Sign In"></input></p>
</form>

{% endblock %}

在我们的模板与常规的 HTML 表单之间存在一些有意思的不同处。模板期望一个实例化,刚才创建的表单类的表单对象存储成一个模板参数,称为 form。当我们编写渲染这个模板的视图函数的时候,我们将会特别注意传送这个模板参数到模板中。

form.hidden_tag() 模板参数将被替换为一个隐藏字段,用来是实现在配置中激活的 CSRF 保护。如果你已经激活了 CSRF ,这个字段需要出现在你所有的表单中。

我们表单中实际的字段也将会被表单对象渲染,你只必须在字段应该被插入的地方指明一个 {{form.field_name}} 模板参数。某些字段是可以带参数的。在我们的例子中,我们要求表单生成一个 80 个字符宽度的 openid 字段。

因为我们并没有在表单中定义提交按钮,我们必须按照普通的字段来定义。提交字段实际并不携带数据因此没有必要在表单类中定义。

表单视图

在我们看到我们表单前的最后就是编写渲染模板的视图函数的代码。

实际上这是十分简单,因为我们只需要把一个表单对象传入模板中。这就是我们新的视图函数,文件位置是 app/views.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from app import app
from flask import render_template, flash, redirect
from .forms import LoginForm

@app.route('/login', methods = ['GET', 'POST'])

def login():
    form = LoginForm()
    return render_template('login.html',
            title = 'Sign In',
            form = form)

所以基本上,我们已经导入 LoginForm 类,从这个类实例化一个对象,接着把它传入到模板中。这就是我渲染表单所有要做的。

这里有一个新的知识点就是路由装饰器的 method 参数。参数告诉 Flask 这个视图函数接受 GET 和 POST 请求。如果不带参数的话,视图只接受 GET 请求。

接下来,你可以运行程序了,然后会看到如下页面:


因为我们还没有编写接受数据的代码,因此此时按提交按钮不会有任何作用。

接受表单数据

Flask-WTF 使得工作变得简单的另外一点就是处理提交的数据。这里是我们登录视图函数更新的版本,它验证并且存储表单数据,文件位置是 app/views.py

@app.route('/login', methods = ['GET', 'POST'])

def login():
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data))
        return redirect('/index')
    return render_template('login.html',
            title = 'Sign In',
            form = form)

validate_on_submit 方法做了所有表单处理工作。当表单正在展示给用户的时候调用它,它会返回 False

如果 validate_on_submit 在表单提交请求中被调用,它将会收集所有的数据,对字段进行验证,如果所有的事情都通过的话,它将会返回 True ,表示数据都是合法的。这就是说嘛数据是安全的,并且被应用程序给接受了。

如果至少一个字段验证失败的话,那么它将会返回 False ,接着表单会重新呈现给用户,这也将给用户一次机会去修改错误。我们将会得到当验证失败后如何显示错误信息。

validate_on_submit 返回 True,我们的登录视图函数调用了两个新的函数,导入自 Flask。flash 函数是一种快速的方式下呈现给用户的页面上显示一个消息。在我们的例子中,我将会使用它来调试,因为我们目前还不具备用户登录的必备的基础设施,相反我们将会用它来显示提交的数据。flash 函数在生产服务器上也是十分有作用的,用来提供反馈给用户有关的行动。

闪现的消息将不会自动地出现在我们的页面上,我们的模板需要加入展示消息的内容。我们将添加这些消息到我们的基础模板中,这样所有的模板都能继承这个函数。这是更新后的基础模板,文件位置是 app/templates/base.html

<html>
  <head>
    {% if title %}
    <title>{{title}} - microblog</title>
    {% else %}
    <title>microblog</title>
    {% endif %}
  </head>
  <body>
    <div>Microblog: <a href="/index">Home</a></div>
    <hr>
    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <ul>
    {% for message in messages %}
        <li>{{ message }} </li>
    {% endfor %}
    </ul>
    {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>
</html>

显示闪现消息的技术希望是不言自明的。

在我们登录视图这里使用的其它新的函数就是 redirect。这个函数告诉网页浏览器引导到一个不同的页面而不是请求的页面。在我们的视图函数中我们用它重定向到前面已经完成的首页上。要注意地是,闪现消息将会显示即使视图函数是以重定向结束。

是到了启动应用程序的时候,测试下表单是如何工作的。确保您尝试提交表单的时候,OpenID 字段为空,看看 Required 验证器是如何中断提交的过程。

加强字段验证

现阶段的应用程序,如果表单提交不合理的数据将不会被接受。相反,会返回表单让用户提交合法的数据。这确实是我们想要的。

然后,好像我们缺少了一个提示用户表单哪里出错了。幸运的是,Flask-WTF 也能够轻易地做到这一点。

当字段验证失败的时候, Flask-WTF 会向表单对象中添加描述性的错误信息。这些信息是可以在模板中使用的,因此我们只需要增加一些逻辑来获取它。

这就是我们含有字段验证信息的登录模板(文件 app/templates/login.html):

<!-- extend base layout -->
{% extends "base.html" %}

{% block content %}
  <h1>Sign In</h1>
  <form action="" method="post" name="login">
      {{ form.hidden_tag() }}
      <p>
          Please enter your OpenID:<br>
          {{ form.openid(size=80) }}<br>
          {% for error in form.openid.errors %}
            <span style="color: red;">[{{ error }}]</span>
          {% endfor %}<br>
      </p>
      <p>{{ form.remember_me }} Remember Me</p>
      <p><input type="submit" value="Sign In"></p>
  </form>
{% endblock %}

唯一的变化就是我们增加了一个循环获取验证 openid 字段的信息。通常情况下,任何需要验证的字段都会把错误信息放入form.field_name.errors 下。在我们的例子中,我们使用 form.openid.errors 。我们以红色的字体颜色显示这些错误信息以引起用户的注意。

处理 OpenIDs

事实上,很多用户并不知道他们已经有一些 OpenIDs。一些大的互联网服务提供商支持 OpenID 认证自己的会员这并不是众所周知的。比如,如果你有一个 Google 的账号,你也就有了一个它们的 OpenID。

为了让用户更方便地使用这些常用的 OpenID 登录到我们的网站,我们把它们的链接转成短名称,用户不必手动地输入这些 OpenID。

我首先开始定义一个 OpenID 提供者的列表。我们可以把它们写入我们的配置文件中(文件 config ):

CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'

OPENID_PROVIDERS = [ 
{ 'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id' }, 
{ 'name': 'Yahoo', 'url': 'https://me.yahoo.com' },
 { 'name': 'AOL', 'url': 'http://openid.aol.com/<username>' }, 
{ 'name': 'Flickr', 'url': 'http://www.flickr.com/<username>' }, 
{ 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }]

现在让我们看看如何在我们登录视图函数中使用它们:

@app.route('/login', methods = ['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data))
        return redirect('/index')
    return render_template('login.html',
        title = 'Sign In',
        form = form,
        providers = app.config['OPENID_PROVIDERS'])

我们从配置中获取 OPENID_PROVIDERS,接着把它作为 render_template 中一个参数传入模板中。

我敢确信你们已经猜到了,我们还需要多做一步来达到目的。我们现在就来说明如何在登录模板中渲染这些提供商的链接(文件app/templates/login.html):

<!-- extend base layout -->
{% extends "base.html" %}

{% block content %}
<script type="text/javascript">
function set_openid(openid, pr)
{
    u = openid.search('<username>')
    if (u != -1) {
        // openid requires username
        user = prompt('Enter your ' + pr + ' username:')
        openid = openid.substr(0, u) + user
    }
    form = document.forms['login'];
    form.elements['openid'].value = openid
}
</script>
<h1>Sign In</h1>
<form action="" method="post" name="login">
    {{ form.hidden_tag() }}
    <p>
        Please enter your OpenID, or select one of the providers below:<br>
        {{ form.openid(size=80) }}
        {% for error in form.openid.errors %}
          <span style="color: red;">[{{error}}]</span>
        {% endfor %}<br>
        |{% for pr in providers %}
          <a href="javascript:set_openid('{{ pr.url }}', '{{ pr.name }}');">{{ pr.name }}</a> |
        {% endfor %}
    </p>
    <p>{{ form.remember_me }} Remember Me</p>
    <p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}

模板变得跟刚才不一样了。一些 OpenIDs 含有用户名,因此对于这些用户,我们必须利用 javascript 的魔力提示用户输入用户名并且组成 OpenIDs。当用户点击一个 OpenIDs 提供商的链接并且(可选)输入用户名,该提供商相应的 OpenID 就被写入到文本域中。


参考资料:

Flask web 表单

Flask 文档

本文转载自:http://www.jianshu.com/p/dbfeeda8bddf

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2634
码字总数 82983
作品 0
程序员
看完这篇文章还能不懂Flask这种Web框架吗?

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基...

lemonwater
05/14
0
0
(三)Flask 学习 —— web 表单

web 表单 回顾 在上一章节中,我们定义了一个简单的模板,使用占位符来虚拟了暂未实现的部分,比如用户以及文章等。 在本章我们将要讲述应用程序的特性之一–表单,我们将会详细讨论如何使用...

水果糖
2016/02/25
1K
0
Flask框架 —— 从入门到精通

更新日期 :2016 - 2 - 26 有开源网友提醒,故为了可阅读性更新排版。 Hello World 作者背景 应用程序简介 要求 安装 Flask 在 Flask 中的 “Hello, World” 下一步? 模板 回顾 为什么我们需...

水果糖
2016/02/26
402
0
Flask 使用小结【Updating】

1、最简单的hello world #!/usr/bin/env python encoding: utf-8 from flask import Flaskapp = Flask(name) @app.route('/')def index(): return 'hello world' if name == 'main': app.ru......

大数据之路
2013/10/24
0
0
(五)Flask 学习 —— 用户登录

用户登录 回顾 在上一章中,我们已经创建了数据库以及学会了使用它来存储用户以及 blog,但是我们并没有把它融入我们的应用程序中。在两章以前,我们已经看到如何创建表单并且留下了一个完全...

水果糖
2016/02/25
232
0

没有更多内容

加载失败,请刷新页面

加载更多

linux使用ntfs-3g操作ntfs格式硬盘

Linux内核目前只支持对微软NTFS文件系统的读取。 NTFS-3G 是微软 NTFS 文件系统的一个开源实现,同时支持读和写。NTFS-3G 开发者使用 FUSE 文件系统来辅助开发,同时对可移植性有益。 安装 ...

linuxprobe16
45分钟前
1
0
kubeadm部署kubernetes集群

一、环境要求 这里使用RHEL7.5 master、etcd:192.168.10.101,主机名:master node1:192.168.10.103,主机名:node1 node2:192.168.10.104,主机名:node2 所有机子能基于主机名通信,编辑...

人在艹木中
今天
7
0
Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
2
0
OSChina 周二乱弹 —— 程序员圣衣

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文:分享Skeeter Davis的单曲《The End of the World》 《The End of the World》- Skeeter Davis 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
17
0
[ python import module ] 导入模块

import moudle_name ----> import module_name.py ---> import module_name.py文件路径 -----> sys.path (这里进行查找文件) # from app.web import Personimport app.web.Person as Pe......

_______-
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部