iT邦幫忙

2021 iThome 鐵人賽

DAY 18
0
Modern Web

Flask系列 第 18

Day 18 實作表單 (1)

前言

今天我們要開始使用 Flask-WTF 來做表單,我們要做的表單還不少,但我們每個都會實作。他的概念是用 class 的方式把表單寫起來,然後建立一個表單實體並傳入 render_template 讓 jinja 處理。

我們會加入一個新檔案 forms.py,他會放在 app/ 裡面。

引入

我們先來引入一些跟 Flask-WTF 有關的東西。

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from wtforms.fields.html5 import EmailField
from wtforms.validators import DataRequired, Length, EqualTo, Regexp

一開始我們先引入 FlaskForm,他會是我們之後所有表單繼承的對象。接下來我們引入了好幾個 field,他們基本上就是對應到 HTML 的那些 input type。比較麻煩的是 EmailField 要從 wtforms.fields.html5 引入,之後也會用到一些其他的 field 要從這裡引入,最後我們引入了一些 validator,他們是用來驗證使用者輸入是否正確的,等等我們會一個一個看到。

LoginForm

首先來看看最簡單的登入表單,在這裡面我們只需要叫使用者輸入帳號、密碼,然後按下送出即可。在 Flask-WTF 裡面,這樣就是三個欄位。

class LoginForm(FlaskForm):
    username = StringField(
        "Username", validators=[DataRequired()], render_kw={"placeholder": "Username"}
    )
    password = PasswordField(
        "Password", validators=[DataRequired()], render_kw={"placeholder": "Password"}
    )
    submit = SubmitField("Login")

我們定義了一個 LoginForm,用來處理使用者的登入,接著如剛剛所說,他繼承了 FLaskForm。

他有三個欄位,分別是 usernamepasswordsubmit,這些名字並不會顯示在網頁上,但是我們在處理模板及抓表單資料的時候會用到。接下來我們會分開解釋他們及其參數。

  • 第一個是 username,很明顯就是用來填使用者名稱的。他是一個 StringField,就是放文字的欄位。而他的第一個參數是這個欄位的名字,後面在 jinja 那邊會用到,他在 HTML 是 label 的角色。validators 是規定這個欄位要遵守的規則,他是一個 list,Flask-WTF 會一一檢查,沒過就會視為無效,到時候在寫藍圖的時候會看到怎麼判斷。這邊使用的是 DataRequired,對應到 HTML 就是 input 裡面的 required。而他的確會在 HTML 的部份加上 required,但就算手動把它移掉,到後端他還是會檢查一次。最後是 render_kw,基本上它就是一些額外的參數,像此處就是指定他的 placeholder,這樣在 HTML 那邊就會顯示出 placeholder="Username",同理,如果想加入 id,就可以在 render_kw 裡面加上 "id": "cat" 之類的東西。
  • 第二個是密碼的欄位,基本上他跟前面的使用者名稱是一樣的,他們的差別就只有他是一個 PasswordField,也就是密碼欄位,所以它會自動在 HTML 變成 type="password"
  • 第三個不是一個使用者看起來像欄位的東西,他是提交出去的按鈕,也就是說 type="submit",而他會用 SubmitField 這個東西。他的第一個參數跟前兩個差不多,就是他的名字,但這個名字就會直接變成這個 submit 按鈕的文字,在 HTML 就是他的 value

RegisterForm

剛剛第一個表單蠻簡單的,就少少三個欄位,但接下來要寫的註冊帳號表單就沒這麼輕鬆了,先來看看程式碼吧。

class RegisterForm(FlaskForm):
    username = StringField(
        "Username",
        validators=[
            DataRequired(),
            Length(min=4, max=30, message="The name should be 4 to 30 letters long."),
            Regexp(
                "[a-zA-Z0-9_]+",
                message="Only letters, numbers and underscore are allowed in username.",
            ),
        ],
        render_kw={"placeholder": "Username"},
    )
    password = PasswordField(
        "Password",
        validators=[
            DataRequired(),
            Length(min=6, message="The password must contain at least 6 characters."),
        ],
        render_kw={"placeholder": "Password"},
    )
    repeat_password = PasswordField(
        "Repeat Password",
        validators=[
            DataRequired(),
            EqualTo("password", message="Passwords not match."),
        ],
        render_kw={"placeholder": "Repeat Password"},
    )
    email = EmailField(
        "Email", validators=[DataRequired()], render_kw={"placeholder": "Email"}
    )
    submit = SubmitField("Register")

其實這次也就只有五個欄位,但是每一個欄位都有一堆麻煩的設定,我們一個一個來看。

  • 第一個欄位是使用者名稱,我們在 validators 加了不少東西。首先是剛剛就有的 DataRequired,在此不再多說了。接下來是 Length,它是用來限制長度的,maxmin 分別代表上下限,後面的 message 是當這個條件不被滿足時所要跳出的訊息 (在 DataRequired 也可以指定 message,在寫藍圖的時候我們會處理這個訊息並 flash 到前端。最後一個是 Regexp,就是正規表示式 (regular expression) 的意思,在這邊我們限制這個使用者名稱只能由英文字母、數字、下底線組成,如同下面的 message 所寫。
  • 第二個是密碼,一樣要有 DataRequired,同時也限制最短密碼要有六個字元,沒有上限。
    第三個是確認密碼的欄位,所以在他的 validators 我們加入了 EqualTo,他的第一個參數是要跟哪一個 field 有相同的值,要放的是變數名稱,但用的是字串 ("password"),而不是變數本身 (password)。
  • 第四個是填寫電子郵件的欄位,剛剛沒有出現過,要使用 EmailField
  • 最後一個欄位跟剛剛接近,就是提交的按鈕,但在此處我們 value 設成 Register

References

Automatically setting the id HTML attribute of a form element in flask-wtforms
HTML input Tag


上一篇
Day 17 實作測試 (3)
下一篇
Day 19 實作表單 (2)
系列文
Flask30

尚未有邦友留言

立即登入留言