使用 WTForms 進行表單驗證

當您必須處理由瀏覽器視圖提交的表單資料時,程式碼很快就會變得難以閱讀。市面上有一些程式庫旨在使此過程更易於管理。其中之一是 WTForms,我們將在此處理它。如果您發現自己處於需要處理許多表單的情況,您可能想試試看。

當您使用 WTForms 時,您必須首先將您的表單定義為類別。我建議將應用程式分解為多個模組(將大型應用程式作為套件)來做到這一點,並為表單新增一個單獨的模組。

透過擴充套件充分利用 WTForms

Flask-WTF 擴充套件擴展了這種模式,並新增了一些小助手,使表單和 Flask 的協作更加有趣。您可以從 PyPI 取得它。

表單

這是一個典型註冊頁面的範例表單

from wtforms import Form, BooleanField, StringField, PasswordField, validators

class RegistrationForm(Form):
    username = StringField('Username', [validators.Length(min=4, max=25)])
    email = StringField('Email Address', [validators.Length(min=6, max=35)])
    password = PasswordField('New Password', [
        validators.DataRequired(),
        validators.EqualTo('confirm', message='Passwords must match')
    ])
    confirm = PasswordField('Repeat Password')
    accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])

在視圖中

在視圖函式中,此表單的使用方式如下所示

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data,
                    form.password.data)
        db_session.add(user)
        flash('Thanks for registering')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

請注意,我們這裡暗示視圖正在使用 SQLAlchemy(Flask 中的 SQLAlchemy),但這當然不是必要條件。請根據需要調整程式碼。

注意事項

  1. 如果資料是透過 HTTP POST 方法提交,則從請求 form 值建立表單;如果資料是作為 GET 提交,則從請求 args 值建立表單。

  2. 要驗證資料,請呼叫 validate() 方法,如果資料驗證成功,它將傳回 True,否則傳回 False

  3. 要從表單存取個別值,請存取 form.<NAME>.data

範本中的表單

現在轉到範本端。當您將表單傳遞到範本時,您可以輕鬆地在那裡呈現它們。查看以下範例範本,了解這有多麼容易。WTForms 已經為我們完成了一半的表單生成工作。為了使其更美觀,我們可以編寫一個巨集,以呈現帶有標籤的欄位,以及如果有任何錯誤,則呈現錯誤列表。

以下是一個範例 _formhelpers.html 範本,其中包含這樣的巨集

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

此巨集接受一些關鍵字引數,這些引數會轉發到 WTForm 的欄位函式,該函式為我們呈現欄位。關鍵字引數將作為 HTML 屬性插入。因此,例如,您可以呼叫 render_field(form.username, class='username') 以將類別新增到輸入元素。請注意,WTForms 傳回標準 Python 字串,因此我們必須告訴 Jinja2 此資料已經使用 |safe 篩選器進行 HTML 跳脫。

這是我們上面使用的函式的 register.html 範本,它利用了 _formhelpers.html 範本

{% from "_formhelpers.html" import render_field %}
<form method=post>
  <dl>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.accept_tos) }}
  </dl>
  <p><input type=submit value=Register>
</form>

有關 WTForms 的更多資訊,請前往 WTForms 網站