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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章