首頁 > 軟體

Flask表單與表單驗證實現流程介紹

2022-09-06 18:06:18

表單介紹

說到表單,在HTML中表單的建立時通過<form>標籤實現的,在<form>標籤內部,欄位通過使用<input>標籤等定義。比如一個表單內部有使用者名稱,密碼框這些,都是通過<input><label>標籤等實現的。

一個簡單的表單:

<form>
First name:<br>
<input type="text" name="firstname">
<br>
Last name:<br>
<input type="text" name="lastname">
</form>

將表單提交給伺服器端處理時,伺服器端需要驗證表單中的欄位的取值是否符合要求。

在 Python 的 Web 開發中,表單內部的欄位標籤之類的,就不再使用HTML標籤來寫了,而是通過python類實現。

WTForms在python中使用類定義表單,然後直接通過類定義生成對應的HTML程式碼,這種方式更加方便,而且使表單更易於重用。除非是非常簡單的程式,或者想讓表單的定義更加靈活,否則一般不會在模板中直接使用HTML程式碼寫表單。

WTForms 和 Flask-WTF

WTForms 是一個靈活的表單驗證和表單渲染的庫,它的主要功能:

  • 驗證表單中的欄位的取值是否符合要求;
  • 渲染輸出表單的 HTML 程式碼

WTForms 可以與任意的 Web 框架和模板引擎一起使用。 在 Flask 框架或者 Django 框架中,都可以使用 WTForms。

Flask-WTF 在 WTForms 的基礎上提供了一些擴充套件,可以方便的在 Flask 框架中生成表單。

建立表單

下面直接用程式碼講解如何建立表單。

首先,我們的目標是這樣一個頁面

一個簡單的登入頁面,讓使用者輸入使用者名稱,密碼,同時對使用者名稱和密碼進行驗證,驗證成功就輸出,驗證不成功需要重新輸入,並提示錯誤資訊。

首先,這是一個表單,表單內有一些文字,有文字方塊,有登入按鈕,這些都是通過python中的表單類建立的,使用的正是flask-wtf模組建立的。

先匯入需要的模組

#匯入表單類
from flask_wtf import FlaskForm
#匯入欄位類
from wtforms import StringField,SubmitField,PasswordField
#匯入驗證器類
from wtforms.validators import DataRequired,Length,Regexp
class LoginForm(FlaskForm):
    '''
    這些欄位物件會被渲染為html標籤
    範例化一個文字欄位物件,設定引數
    label:這個值可以拿出來放在標籤前面顯示
    validators=[]驗證器列表,範例化的驗證器物件,裡面又可以設定引數
    '''
    #使用者名稱欄位
    username = StringField(
        label='使用者名稱',
        validators=[
            DataRequired(message='使用者名稱不能為空'),
            Length(3,20,message='使用者名稱長度在3-20個字元')
        ]
    )
    password = PasswordField(
        label='密碼',
        validators=[
            DataRequired(message='密碼不能為空'),
            Length(3,20,message='密碼長度在3-20個字元'),
 			Regexp(r'^[a-z0-9A-Z]+$',message='密碼只能有字母,數位,下劃線組成')
        ]
    )
    submit = SubmitField(label='登入')

我們建立了一個類LoginForm,它是一個表單類,繼承了FlaskForm,這個表單中包含一個使用者名稱username欄位,密碼password欄位,還有一個提交按鈕submit,這三個欄位作為了類LoginForm的三個屬性。

表單欄位

我們發現使用者名稱,密碼這些實際是文字方塊,既然不用HTML程式碼實現,那麼怎麼實現呢?

使用的就是WTForms中的各種欄位類,比如這裡:

username = StringField()

StringField()是WTForms 支援表單欄位類,它表示文字欄位,這樣一個欄位會被渲染為

<input id="username" name="username" type="text" value="">

注意:範例化物件的名稱是username ,被渲染後的input標籤中的idname屬性值都叫username

WTForms 支援如下型別的表單欄位:

這只是一部分,還有很多其他支援的欄位。

接著看程式碼:

    username = StringField(
        label='使用者名稱',
        validators=[
            DataRequired(message='使用者名稱不能為空'),
            Length(3,20,message='使用者名稱長度在3-20個字元')
        ]
    )

驗證器

StringField類需要傳遞一些引數:

label='使用者名稱' ,這個引數可以直接在模板頁面中顯示,使用form.username.label,把它放在文字方塊的前面,像下面這樣:

validators=[ ] 這個參數列示對這個欄位使用的驗證器列表。驗證器就是對這個欄位使用那些驗證,比如這裡DataRequired,Length兩個驗證器類,同樣驗證器類需要範例化然後傳入引數。比如:

Length(3,20,message='使用者名稱長度在3-20個字元')

限定長度在3-20字元,如果驗證不通過,就彈出錯誤資訊:message='使用者名稱長度在6-20個字元'

驗證器也有很多型別,常見的驗證器類有:

還可以自定義驗證器類等等。

我們建立了一個單獨的檔案loginform.py

from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,Regexp,Length
class LoginForm(FlaskForm):
    #<input id="username1" maxlength="20" minlength="3" name="username1" required type="text" value="">
    username = StringField(
        label='使用者名稱',
        validators=[
            DataRequired(message='使用者名稱不能為空'),
            Length(3,20,message='使用者名稱長度在3-20個字元')
        ]
    )
    password = PasswordField(
        label='密碼',
        validators=[
            DataRequired(message='密碼不能為空'),
            Length(3,20,message='密碼長度在3-20個字元'),
            Regexp(r'^[a-z0-9A-Z]+$',message='密碼只能有字母,數位,下劃線組成')
        ]
    )
    submit = SubmitField(label='登入')

表單類建立好之後,可以做一個簡單的測試:

把這個表單顯示出來

首先,我們在app.py檔案中:

from flask import Flask,render_template,request
from loginform import LoginForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
@app.route('/',methods=['GET','POST'])
def login():
    loginform = LoginForm()
    if request.method == 'GET':
        return render_template('login.html',form = loginform)
    return 'hello'
if __name__ == '__main__':
    app.run()

app.config['SECRET_KEY'] = 'hard to guess string'
用於防範 CSRF 攻擊,具體的我也不清楚,就不再細說了,總之需要設定

接著,在根路由下/,有檢視函數login,存取這個路由的方法可以是GET,或者POST。首先假設是GET,我們就需要把之前的表單渲染出來,具體的做法就是:

使用建立的表單類LoginForm範例化一個表單物件loginform ,如果請求方法是GET,就去渲染login.html,然後表單物件作為引數傳遞過去。所以我們還需要設計一下login.html檔案。

login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登入頁面</title>
</head>
<body>
<form action="{{ url_for('login') }}" method="post">
    <table>
        <tbody>
        <tr>
            <td>{{ form.username.label }}</td>
            <td>{{ form.username }}</td>
            <td>{% for err in form.username.errors %}
                {{ err }}
                {% endfor %}
            </td>
        <td>{{ form.test }}</td>
        </tr>
        <tr>
            <td>{{ form.password.label }}</td>
            <td>{{ form.password }}</td>
            <td>{% for err in form.password.errors %}
                {{ err }}
                {% endfor %}
            </td>
        </tr>
        <tr>
            <td>{{ form.submit }}</td>
        </tr>
        {{ form.hidden_tag() }}
        </tbody>
    </table>
</form>
</body>
</html>

這裡使用了一個表格佈局,然後表單的action="{{ url_for('login') }}" method="post",設定了表單的提交路徑,以及提交方法。

    <td>{{ form.username.label }}</td>#拿到username的label值顯示出來
    <td>{{ form.username }}</td>#顯示username這個欄位
    <td>{% for err in form.username.errors %}#這是錯誤資訊,如果驗證不通過會顯示錯誤資訊
        {{ err }}
        {% endfor %}
    </td>

最後,還要注意到: {{ form.hidden_tag() }}, 用於防範 CSRF 攻擊,生成 <input id=“csrf_token”/> 標籤。總之必須要加上,不加上,後面驗證資料的時候會出問題。

接著,執行app.py,存取根路徑/,則是GET方法存取,會渲染出login.html檔案。

接著,我們需要實現,使用者輸入資料,我們進行驗證,驗證不成功就提示錯誤資訊,驗證成功就登入成功。

回到表單類中,我們可以發現使用的驗證器有這幾種:

其中,DataRequired,Length直接被渲染為HTML中input標籤的屬性:

maxlength="" minlength="" required

這時候驗證就是在瀏覽器上完成的了,而不是在伺服器。使用者端方式可以實時動態的提示使用者輸入是否正確,只有使用者輸入正確後才會將表單資料傳送給伺服器。使用者端驗證可以增強使用者體驗,降低伺服器負載。

參考書上說,Flask程式中使用WTForms實現的就是伺服器驗證,但是有些欄位又會被渲染為HTML5的屬性,所以也不全是伺服器驗證。

這就是瀏覽器給出的驗證提示

但是正則驗證器,確實是在伺服器端完成驗證的

Regexp(r'^[a-z0-9A-Z]+$',message='密碼只能有字母,數位,下劃線組成')

那麼怎麼在伺服器驗證資料呢,首先,我們的資料會提交到/路徑,使用的是POST方法。

表單類物件loginform,有一個驗證方法,loginform.validate(),呼叫這個方法時,會去呼叫你每一個欄位中使用的每一個驗證器去驗證資料,全部驗證通過返回True,失敗返回False。

@app.route('/',methods=['GET','POST'])
def login():
    loginform = LoginForm()
    if request.method == 'GET':
        return render_template('login.html',form = loginform)
    elif request.method == 'POST' and loginform.validate():
        return f'使用者 {loginform.username.data}登入成功'
    else:
        return render_template('login.html',form = loginform)
  • 如果請求方法時GET,直接渲染表單
  • 如果請求方法時POST,並且loginform.validate()==True,表示驗證通過,這時候我們返回登入成功,同時使用loginform.username.data可以拿到使用者輸入的使用者名稱。
  • 否則,驗證失敗,再次渲染這個表單,注意:這時候,呼叫了validate()方法,返回False,產生了錯誤資訊,錯誤資訊在form.username.errors,是一個列表,這時候login.html中的錯誤資訊列表就是有輸出了。

測試一下:我的密碼欄位設定了正則驗證,只允許輸入字母數位下劃線,而且字元個數在3-20個。

首先,不填寫欄位,瀏覽器端會自動驗證

輸入正確格式的密碼:

輸入錯誤格式的密碼:

到此這篇關於Flask表單與表單驗證實現流程介紹的文章就介紹到這了,更多相關Flask表單內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com