Flask实践Step by Step -- Web表单

Flask Web表单

上一节我们定义了一个简单的模板,并看到了实际运行的效果,接下来我们来看一下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 %}

运行截图 !

写在最后

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

发布了43 篇原创文章 · 获赞 7 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章