在Web應用中,表單是用戶與服務器交互的核心方式之一——比如登錄、註冊、提交反饋等場景都需要表單。Flask本身不直接提供表單處理功能,但通過擴展庫Flask-WTF(基於WTForms),可以輕鬆實現表單創建、數據驗證和安全處理。本文將從零開始,一步步帶你掌握Flask中表單處理與驗證的核心知識。
一、環境準備:安裝必要庫¶
首先確保安裝了Flask和Flask-WTF。打開終端,執行以下命令:
pip install flask flask-wtf
Flask:Web框架基礎。Flask-WTF:Flask的表單擴展,內置了WTForms(強大的表單處理庫)和CSRF保護(防止跨站請求僞造攻擊)。
二、核心概念:表單類與驗證器¶
我們通過表單類定義表單結構和驗證規則,每個字段(如用戶名、密碼)對應一個類屬性,每個屬性可以附加多個驗證器(如非空、郵箱格式、長度限制等)。
1. 定義表單類¶
以“用戶註冊”表單爲例,創建一個RegistrationForm類,繼承FlaskForm(Flask-WTF的基類)。每個字段通過StringField、PasswordField等類型定義,並用validators參數添加驗證規則。
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length, EqualTo
class RegistrationForm(FlaskForm):
# 用戶名:非空,長度4-20
username = StringField('用戶名',
validators=[DataRequired(), Length(min=4, max=20)])
# 郵箱:非空,格式驗證
email = StringField('郵箱',
validators=[DataRequired(), Email()])
# 密碼:非空,長度8-20
password = PasswordField('密碼',
validators=[DataRequired(), Length(min=8, max=20)])
# 確認密碼:與密碼一致,非空
confirm_password = PasswordField('確認密碼',
validators=[DataRequired(), EqualTo('password',
message='兩次密碼輸入不一致')])
# 提交按鈕
submit = SubmitField('註冊')
關鍵說明:
- StringField:普通文本輸入框(如用戶名、郵箱)。
- PasswordField:密碼輸入框(自動隱藏輸入內容)。
- SubmitField:提交按鈕。
- validators:驗證器列表,每個驗證器負責檢查字段的合法性:
- DataRequired():字段不能爲空。
- Email():驗證郵箱格式。
- Length(min, max):限制字符串長度。
- EqualTo('field'):確保與指定字段值一致(如確認密碼)。
三、在Flask中渲染表單¶
定義好表單類後,需要在視圖函數中實例化表單,並在模板中渲染。
1. 視圖函數處理表單¶
在app.py中定義視圖函數,處理GET/POST請求:
from flask import Flask, render_template, redirect, url_for, flash
from forms import RegistrationForm # 導入表單類
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here' # 用於CSRF保護,需隨機字符串
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm() # 實例化表單類
if form.validate_on_submit(): # 檢查是否爲POST請求且數據合法
# 數據合法:獲取表單數據(如form.username.data)
username = form.username.data
email = form.email.data
password = form.password.data
# 這裏可添加後續操作(如存入數據庫)
flash('註冊成功!') # 提示信息(需在模板中顯示)
return redirect(url_for('index')) # 重定向到首頁
return render_template('register.html', form=form) # 渲染模板,傳入表單
if __name__ == '__main__':
app.run(debug=True)
2. 模板渲染表單(register.html)¶
使用Jinja2模板語法渲染表單,需注意:
- form.hidden_tag():生成CSRF令牌(Flask-WTF自動添加,防止惡意提交)。
- 顯示字段標籤、輸入框和錯誤信息。
<!DOCTYPE html>
<html>
<head>
<title>註冊</title>
</head>
<body>
<h1>用戶註冊</h1>
<!-- 顯示提示信息 -->
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div style="color: green;">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<!-- 渲染表單 -->
<form method="POST">
{{ form.hidden_tag() }} <!-- 必須添加,否則CSRF驗證失敗 -->
<!-- 用戶名 -->
<div>
{{ form.username.label }} <!-- 標籤 -->
{{ form.username(size=32) }} <!-- 輸入框 -->
<!-- 顯示錯誤信息 -->
{% for error in form.username.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
<!-- 郵箱 -->
<div>
{{ form.email.label }}
{{ form.email(size=64) }}
{% for error in form.email.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
<!-- 密碼 -->
<div>
{{ form.password.label }}
{{ form.password(size=32) }}
{% for error in form.password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
<!-- 確認密碼 -->
<div>
{{ form.confirm_password.label }}
{{ form.confirm_password(size=32) }}
{% for error in form.confirm_password.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
</div>
<!-- 提交按鈕 -->
<div>{{ form.submit() }}</div>
</form>
</body>
</html>
四、處理表單提交與驗證¶
當用戶提交表單時,Flask-WTF會自動完成以下步驟:
1. 檢查請求方法是否爲POST。
2. 驗證CSRF令牌(防止僞造請求)。
3. 運行所有validators檢查數據合法性。
4. 若所有驗證通過,form.validate_on_submit()返回True,可處理數據。
關鍵流程¶
- GET請求:渲染空表單(用戶首次訪問)。
- POST請求:
- 若驗證通過:獲取數據(
form.xxx.data),執行後續操作(如存入數據庫)。 - 若驗證失敗:模板中顯示錯誤信息(通過
form.xxx.errors循環輸出)。
五、完整示例:從表單到數據庫¶
若需將用戶數據存入數據庫,可結合SQLAlchemy(Flask的ORM擴展)。這裏簡化示例,假設已安裝flask-sqlalchemy:
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(20), nullable=False)
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
# 檢查用戶名/郵箱是否已存在(可選)
existing_user = User.query.filter_by(username=form.username.data).first()
if existing_user:
flash('用戶名已存在!')
return redirect(url_for('register'))
# 創建新用戶並保存
new_user = User(
username=form.username.data,
email=form.email.data,
password=form.password.data # 實際項目中需加密存儲
)
db.session.add(new_user)
db.session.commit()
flash('註冊成功!')
return redirect(url_for('index'))
return render_template('register.html', form=form)
六、總結¶
Flask表單處理的核心步驟:
1. 定義表單類:用FlaskForm和WTForms字段,添加驗證器。
2. 視圖函數處理:實例化表單,判斷請求方法,驗證數據。
3. 模板渲染:用form.hidden_tag()生成CSRF令牌,顯示字段和錯誤信息。
4. 數據處理:驗證通過後,獲取數據並執行後續操作(如數據庫存儲)。
通過WTForms的驗證器,可輕鬆實現非空、格式、長度等校驗,結合Flask-WTF的CSRF保護,能快速構建安全可靠的表單系統。
提示:初學者可先從簡單場景(如登錄表單)入手,逐步掌握複雜驗證(如文件上傳、多字段關聯)。Flask-WTF文檔(https://flask-wtf.readthedocs.io/)和WTForms文檔(https://wtforms.readthedocs.io/)是進階學習的好資源。