# Flask實作_ext_03_Flask-WTF_表單建立 ###### tags: `flask` `flask_ext` `python` `wtform` ## 說明 :::danger 官方文件: * [Flask-wtf](https://flask-wtf.readthedocs.io/en/stable/) ::: 表單類元件在網頁設計中是不可或缺的一個元素,雖然可以透過`request.form`來取得前端的表單,但不免俗的還是要自己硬刻一堆重覆性質的Html。 `Flask-wtf`除了可以減化這類工作之外,它還預設有避免`CSRF`攻擊的功能,這對資訊安全上有絕對的幫助。 ## 安裝 ```python= pip install flask-wtf ``` 透過`pip`安裝`flask-wtf`會自動將相依套件`WTForms`下載安裝,實作上必需要設置Flask參數`SECRET_KEY`,否則會報錯,如下設置: ```python from flask import Flask app = Flask(__name__) app.config('SECRET_KEY') = 'your key values' ``` ## 範例 `Flask-wtf`是一個類別函數,一切都從繼承`FlaskForm`開始,再各別從`wtforms`去引入需求的欄位類別以及驗證。 建立一個新的Python文件,檔案名稱為`view_form.py`,相關作業說明如註解,如下: ```python= # 引入flask_wtf from flask_wtf import FlaskForm # 各別引入需求欄位類別 from wtforms import StringField, SubmitField from wtforms.fields.html5 import EmailField # 引入驗證 from wtforms.validators import DataRequired, Email # 從繼承FlaskForm開始 class UserForm(FlaskForm): username = StringField('UserName', validators=[DataRequired(message='Not Null')]) email = EmailField('Email', validators=[DataRequired(message='Not Null')]) submit = SubmitField('Submit') ``` 第11行:建置一個字串欄位,並利用`validators`來設置欄位的驗證,驗證項目為`DataRequired`,代表必填,最後是當驗證失敗的時候就出現驗證失敗的訊息`message` 現在讓我們加入一個啟動Flask的Python文件,命名為`flask_start.py`,如下: ```python= from flask import Flask, render_template # 引入form類別 from view_form import UserForm app = Flask(__name__) @app.route('/user', methods=['GET', 'POST']) def user(): form = UserForm() # flask_wtf類中提供判斷是否表單提交過來的method,不需要自行利用request.method來做判斷 if form.validate_on_submit(): return 'Success Submit' # 如果不是提交過來的表單,就是GET,這時候就回傳user.html網頁 return render_template('user.html', form=form) if __name__ == '__main__': app.debug = True app.run() ``` 第14行:回傳渲染網頁`user.html`,並傳遞了一個表單物件參數`form`,這讓我們可以在Html文件中可以利用`jinja2`的語法來操作它 部份註解寫在程式碼上,其中`form.validate_on_submit()`是由`flask_wtf`提供的method,可以直接確認`POST`與欄位驗證以及最重要的`CSRF`。 最後在`templates`內加入Html文件,命名為`user.html` ```htmlmixed= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="POST" action="{{ url_for('user') }}" > {{ form.hidden_tag() }} <p>{{ form.username.label }} {{ form.username }} {% if form.username.errors %} {% for error in form.username.errors %} {{ error }} {% endfor %} {% endif %} </p> <p>{{ form.email.label }} {{ form.email }}</p> <p>{{ form.submit.label }} {{ form.submit }}</p> </form> </body> </html> ``` 第9行:這是必填的一個項目,沒有填會出現異常 第10行:`{{ form.username.label }}{{ form.username }}`,`form`是由後端拋到前端來的一個參數,`username`是我們在Form中所設置的屬性名稱,而`label`是該屬性的第一個參數。 一切就緒,這時候執行專案會遇到錯誤訊息如下:  這是因為`flask_wtf`預設需要設置密碼,也是為了避免一開始所說的`CSRF`攻擊。 在`flask_start.py`上,加上`app.config['SECRET_KEY']`的參數設置,如下: ```python= ...上略 if __name__ == '__main__': app.debug = True app.config['SECRET_KEY']='your key' app.run() ``` 重新執行專案,成功的渲染版面,如下圖:  查看原始檔,轉譯的非常完美,如下圖:  故意讓email格式輸入錯誤,如下圖:  這錯誤訊息是因為欄位本身設置為email欄位,這是`html5`預設的卡控機制。 故意讓username是空值,異常訊息如下圖:  透過`field.errors`來取得錯誤訊息之後呈現! ## 總結 利用一個簡單的範例來認識`flask-wtf`,透過參數的傳遞將物件由後端拋到前端,再搭配`jinja2`語法來操作,簡化的程度大到令人感到不可思議,原來開發一個表單可以這麼快速,但這還不足以驚豔,因為下一話我們會搭配`flask-bootstrap`來更快速的開發表單,下面有其它的部份,是簡單的列出`WTForms`支援的欄位清單以及驗證函數,更詳細的當然是請您參閱官方文件說明。 **Flask-WTF_表單建立_進階:**[Flask實作_ext_04_Flask-WTF_表單建立_進階](https://hackmd.io/s/r1pPM7ZXz) ## 其它 ### WTForms支援欄位清單 |類型|說明| |-----|-----| |StringField|字串欄位| |TextAreaField|多行字串欄位| |PasswordField|密碼欄位(出現\*)| |HiddenField|隱藏欄位| |DateField|日期欄位datetime.date| |DateTimeField|日期時間欄位datetime.datetime| |IntegerField|整數欄位| |DecimalField|精度數值欄位decimal.Decimal| |FloatField|浮點數欄位| |BooleanField|布林欄位| |RadioField|單選radio| |SelectField|下拉表單| |SelectMultipleField|下拉表單(可多選)| |FileField|文件上傳欄位| |SubmitField|提交表單按鈕| |FormField|Form中有Form| |FieldList|?| ### WTForms驗證函數 |函數|說明| |-----|-----| |Email|驗證電子郵件欄位| |EqualTo|比較兩欄位數值是否相同| |IPAddress|驗證ip位址| |Length|驗證字串長度| |NumberRange|驗證數值區間| |Optional|?| |DataRequired|必填欄位| |Regexp|以正則式驗證| |URL|驗證網址| |AnyOf|驗證輸入值在列表中| |NoneOf|驗證輸入值不在列表中|
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.