Flask实践Step by Step -- Web表单

Flask开发环境配置
Flask快速入门
Flask实践Step by Step -- 'Hello World'
Flask实践Step by Step -- 模板
Flask实践Step by Step -- Web表单

Flask Web Forms

上一节我们定义了一个简单的模板,并看到了实际运行的效果,接下来我们来看一下Web表单是如何
工作的,Web表单是Web应用程序的基础控件,使用表单可以使用用户写博客,进行登录等

配置

为了使用表单,我们需要使用Flask的一个扩展插件 Flask-WTF 需要先安装 pip install flask-wtf ,
许多Flask扩展需要很多的配置,我需要一个配置文件来进行管理 config.py

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

配置文件中的内容非常简单,需要两项设置即可,WTF_CSRF_ENABLED设置会激活跨站访问保护
这个设置在这个版本中Flask-WTF是默认打开的,为了更安全我们这里还是显示的设置为 True
SECRECT_KEY的设置只有当WTF_CSRF_ENABLED为true时才会需要,为表单验证创建一个密码
token,这个key值尽量设置的复杂一些
接下来就需要Flask读取相关的配置,并且使用这些配置,在Flask的应用程序创建之后(file app/__init__.py)

from flask import Flask

app = Flask(__name__)
app.config.from_object('config')

from app import views

用户登录表单

Flask-WTF的表单是一个集成基类Form的一个类,现在我们需要创建一个登录的表单,需要用到身份认证系统
登录机制不是标准的 用户名/密码 模式,我们在这里引入了 OpendID,OpenID本身已经提供了
很好的验证,我们就不在需要验证密码了,这样可以使网站更安全,需要安装OpenID pip install flask-openid
使用OpenID登录只需要一个字符串,我们还提供了一个 'remember me' 选择框,用户可以选择是否需要浏览器在cookie中记住
用户的选择
写第一个表单 (file app/forms.py)

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两个字段,StringFieldBooleanField,DataRequired是一个验证器
一个方法和一个字段绑定,这个DataRequired验证器只是简单的验证提交的输入内容,这Flask-WTF中还有很多
验证器,后续会继续介绍

表单模板

我们需要一个模板来生成HTML的表单,我们需要创建一个新的模板 (file app/templates/login.html)

{% extends "base.html" %}

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

这个模板中同样是继承base.html,这个模板和普通的HTML页面的表单还是有一些区别的,需要
视图中对应的方法来血染这个模板,form.hidden_tag()会被HTML中的隐藏的域来取代,这个参数
需要把CSRF设置为Enabled状态

表单视图

我们需要一个视图方法来渲染这个模板(file app/views.py)

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

#index view function...

@app.route('/login',methods=['GET','POST'])
def login():
    form = LoginForm()
    return render_template('login.html',
                            title="Sign in",
                            form=form)

需要引入 LoginForm这类,然后实例化,将这个实例化对象作为参数传入到模板中,我们还引入了
flashredirect,可以暂时忽略这两个引用,以后我们会用到,在装饰器中我们加入了 methods
作为参数,告诉Flask我们的这个方法接收 GET和POST请求,保存运行,打开浏览器 访问 http://127.0.0.1:5000/login
看一下实际的效果,暂时我们还没有处理接收数据的处理,所以现在点击提交按钮会没有任何反馈

接收数据

Flask-WTF能够很容易处理从客户端发来的数据,我们需要修改一下 login的方法(file app/views.py)

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

方法 validate_on_submit会处理所有的表单的处理工作,表单展示给用户时会调用这个方法此时会返回 False
当提交请求时,这个方法会接收所有的数据,验证数据的合法性,如果验证全部正确,这个方法会返回True,只要有一个
参数验证不通过,这个方法就会返回 False,稍后我们会展示如何给用户展示错误信息,当 validate_on_submit返回True
时,方法 flash会展示一个快速的信息,在调到下一个页面之前,这个flash的信息不回显示在页面中,我们需要修改模板信息
来显示这个信息(file app/templates/base.html)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    {% if title %}
    <title>{{ title }} - microblog</title>
    {% else %}
    <title>Welcome to microblog</title>
    {% endif %}
  </head>
  <body>
    <div>
      Microblog : <a href="/index">Home</a>
    </div>
    <hr>
    {% with messages = get_flashed_messages()%}
      {% if messages %}
        <ul>
          {% for msg in messages %}
            <li>{{ msg }}</li>
          {% endfor %}
        </ul>
      {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>
</html>

方法get_flashed_messages会接收flash方法发送来的消息,并展示出来,在视图方法中我们还使用另一个
方法 redirect,这个方法会重定向到另一网页地址

改进数据的验证

当用户的输入的信息有误时,希望能够提供给用户友好的错误的信息提示,我们修改一下login的模板(file app/templates/login.html)

{% extends "base.html" %}

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

添加了错误的提示信息

处理OpenIDs

为了是用户更容易的登录网站,我们添加一些openid的连接,儿不需要用户手动的输入OpenID
先定义一些OpenID的提供者,定义在config.py

WTF_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=""%s",remember_me=%s'%
                (form.openid.data,str(form.remember_me.data)))
        return redirect('/index')
    return render_template('login.html',
                            title="Sign in",
                            form=form,
                            providers=app.config['OPENID_PROVIDERS'])

还需要修改对应的模板视图(file app/templates/login.html)

{% extends "base.html" %}

{% block content %}

<script type="text/javascript">
  function set_openid(openid,pr){
    u = openid.search('<username>')
    if(u != -1){
      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 class="" action="" name="login" method="post">
    {{form.hidden_tag()}}
    <p>
      Please enter your OpenID:<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 value="Sign in" type="submit">
    </p>
  </form>
{% endblock %}

运行截图

写在最后

我们队登录的表单做了很多的改进,但是我们还没有真正的登录到系统中,真正的登录我们需要后台的数据库的支持

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容