目錄
通過Flask處理表單
通過Flask-WTF處理表單
通過Flask-WTF驗證表單
通過Flask處理表單
表單是在網頁中搜集用戶信息的各種表單控件的集合區域,表單控件包括文本框、單選框、復選框、提交按鈕等,用于實現客戶端和服務器端之間的數據交互。
利用Flask內置的功能對表單進行處理的過程:
首先在模板文件中通過HTML代碼創建表單,然后通過請求上下文中的request.form對象獲取以及驗證表單數據,最后通過消息閃現給用戶反饋正確或錯誤提示。
例如用戶注冊的案例:
(1)創建一個Flask項目,在項目中新建templates文件夾,在該文件夾下創建模板文件register.html,在該模板文件中使用<form>標簽創建表單。
<h1>注冊頁面</h1>{#給用戶展示不同的消息閃現#}{% macro print_error(type) %}{% for message in get_flashed_messages(category_filter = (type)) %}<p class="error" style="color: red;display:inline;">{{ message }}</p>{% endfor %}{% endmacro %}<form action="" method=post><span>用戶名:</span><br><input type=text name=username>{{ print_error('message') }}{{ print_error('info') }}<br><span>密碼:</span><br><input type=password name=password><br><span>確認密碼:</span><br><input type=password name=password2>{{ print_error('error') }}<br><p><input type=submit value=注冊></p></form>
(2)在app.py文件中定義視圖函數register(),該視圖函數用于展示注冊頁面以及驗證用戶輸入的注冊數據是否符合要求。
@app.route('/register', methods=['GET', 'POST'])
def register():if request.method == 'POST': # 判斷請求方式username = request.form.get('username') # 獲取表單數據password = request.form.get('password')password2 = request.form.get('password2')if not all([username, password, password2]): # 驗證數據的完整性flash('請填入完整信息', category='message')# 驗證輸入的數據是否符合要求elif len(username) < 3 and len(username) > 0 or len(username) > 15:flash('用戶名長度大于3且小于15', category='info')elif password != password2: # 驗證兩次輸入的密碼是否一致flash('密碼不一致', category='error')else:return '注冊成功'return render_template('register.html')
通過Flask-WTF處理表單
處理表單涉及創建表單、驗證表單數據、獲取和保存表單數據、反饋錯誤提示等諸多操作,為了降低處理表單的難度,Flask提供了專門負責處理表單的擴展包——Flask-WTF。
Flask-WTF的安裝
pip install flask-wtf
Flask-WTF是構建于?WTFForms之上的,所以引用的時候:
from flask_wtf import FlaskForm
常用字段類與表單控件的映射關系:
字段類 | 表單控件 | 說明 |
BooleanField | <input?type="checkbox"> | 復選框,值為True或False,默認值為Flase |
DataField | <input?type="text"> | 文本字段,值為datetime.date對象 |
DataTimeField | <input?type="text"> | 文本字段,值為datetime.datetime對象 |
DecimalField | <input?type="text"> | 文本字段,值為decimal.Decimal |
FileField | <input?type="file"> | 文件上傳字段 |
FloatField | <input?type="text"> | 浮點數字段,值為浮點型 |
IntegerField | <input?type="text"> | 整數字段,值為整型 |
RadioField | <input?type="radio"> | 一組單選按鈕 |
SelectField | <select><option></option></select> | 下拉列表 |
SubmitField | <input?type="submit"> | 提交按鈕 |
StringField | <input?type="text"> | 文本字段 |
PasswordField | <input?type="password"> | 密碼文本字段 |
TextAreaField | <?textarea></textarea> | 多行文本字段 |
HiddenField | <input?type="hidden"> | 隱藏文本字段 |
補充:datetime.date和datetime.datetime的區別
datetime.date類代表日期,它包含年、月和日的信息,但不包含具體的時間(小時、分鐘和秒)信息。
datetime.date(year, month, day)構造函數創建一個日期對象,其中year、month和day分別表示年、月和日的整數值。
datetime.datetime類則代表日期和時間,它包含年、月、日以及具體的時間(小時、分鐘和秒)信息。
datetime.datetime(year, month, day, hour=0, minute=0, second=0)構造函數創建一個日期時間對象,其中year、month、day、hour、minute和second分別表示年、月、日、小時、分鐘和秒的整數值。
常用的字段類都繼承自WTForms庫的Field類,可以通過Field類的構造方法實例化所有字段類,以下是一些可配置的參數:
參數 | 說明 |
label | 字段標簽<label>的值,即顯示在輸入控件旁的說明性文字 |
render_kw | 字典類型,用于設置控件的屬性,包括提示信息(placeholder)、高度(height)、寬度(width )、是否獲得焦點(autofocus )等。 |
validators | 列表類型,包含一系列的驗證器,在提交表單數據時,會被列表中的驗證器逐一驗證 |
default | 字符串或可調用對象,為表單字段設置默認值 |
參數validators的值是一個列表,包含了一系列用于驗證表單數據是否有效的驗證器,只有當表單數據滿足驗證器的規則時,數據才能成功提交到服務器。
- 在使用驗證器之前需要先從wtforms.validators模塊中導入相應的類:
驗證器 | 說明 |
DataRequired(message=None) | 驗證數據是否有效,空字符串為無效數據 |
Email(message=None) | 驗證數據是否為電子郵件地址 |
EqualTo(fieldname,message=None) | 驗證兩個字段值是否相同 |
IPAddress(ipv4=True, ipv6=False, message=None) | 驗證數據是否為有效IP地址 |
Length(min=-1,max=-1,message=None) | 驗證輸入值的長度是否在給定的范圍內 |
NumberRange(min=None,max=None,message=None) | 驗證輸入的數字是否在給定的范圍內 |
Optional(strip_whitespace=True) | 允許字段中沒有輸入,將跳過其他驗證函數 |
Regexp(regex,flags=0,message=None) | 使用正則表達式驗證輸入值 |
URL(require_tld=True,message=None) | 驗證URL |
AnyOf(values, message=None,values_formatter=None) | 確保輸入值在可選值列表中 |
NoneOf(values, message=None,values_formatter=None) | 確保輸入值不在可選值列表中 |
?用Flask-WTF創建表單:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
app = Flask(__name__)
class RegisterForm(FlaskForm):username = StringField(label='用戶名:',validators=[DataRequired(message='用戶名不能為空'),Length(3, 15, message='長度應該為3~15')])password = PasswordField('密碼:',validators=[DataRequired(message='密碼不能為空')])password2 = PasswordField('確認密碼:',validators=[DataRequired(message='密碼不能為空'),EqualTo('password', message='兩次密碼不一致')])submit = SubmitField('注冊')
使用Flask-WTF創建了注冊表單,但此時在模板文件中還無法渲染創建的表單。
- 如果希望在模板文件中渲染通過Flask-WTF創建的表單:
?① 需要在視圖函數中將表單類的對象傳遞到模板文件中。
?②在模板文件中獲取表單字段,將表單字段渲染到HTML頁面進行呈現。
#在項目的app.py文件中定義用于傳遞表單類對象的視圖函數
from flask import render_template
#,默認情況下Flask-WTF為每個表單啟用CSRF保護,因此需要在程序中設置密鑰,
這樣可以讓Flask-WTF通過該密鑰生成CSRF令牌,以便用CSRF令牌驗證請求中表單數據的真偽。
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register(): form = RegisterForm() return render_template('register_wtf.html', form=form)#在templates文件夾中創建模板文件register_wtf.html,并在該模板文件中獲取表單字段
<body><h1>注冊頁面</h1><form method="post">{#獲取username對應的標簽名稱#}<span>{{ form.username.label }}</span><br> {{ form.username }}<br> {#調用表單字段渲染為HTML#}<span>{{ form.password.label }}</span><br>{{ form.password }}<br><span>{{ form.password2.label }}</span><br>{{ form.password2 }}<br><p>{{ form.submit }}</p></form>
</body>
則:app.py的完整代碼如下:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
from flask import render_template
app = Flask(__name__)
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():form = RegisterForm()return render_template('register.html', form=form)
class RegisterForm(FlaskForm):username = StringField(label='用戶名:',validators=[DataRequired(message='用戶名不能為空'),Length(3, 15, message='長度應該為3~15')])password = PasswordField('密碼:',validators=[DataRequired(message='密碼不能為空')])password2 = PasswordField('確認密碼:',validators=[DataRequired(message='密碼不能為空'),EqualTo('password', message='兩次密碼不一致')])submit = SubmitField('注冊')if __name__ == '__main__':app.run()
register的完整代碼如下:
<body><h1>注冊頁面</h1><form method="post">{#獲取username對應的標簽名稱#}<span>{{ form.username.label }}</span><br>{{ form.username }}<br> {#調用表單字段渲染為HTML#}<span>{{ form.password.label }}</span><br>{{ form.password }}<br><span>{{ form.password2.label }}</span><br>{{ form.password2 }}<br><p>{{ form.submit }}</p></form>
</body>
得到注冊頁面為:
通過Flask-WTF驗證表單
表單數據驗證分為客戶端驗證和服務端驗證
客戶端驗證是指客戶端(瀏覽器)對用戶提交的數據進行校驗。客戶端驗證可以通過多種方式進行驗證,包括使用HTML5內置的驗證屬性、JavaScript表單驗證庫等。客戶端驗證可以實時動態提示用戶輸入是否正確,只有用戶輸入正確后才會將表單數據發送給服務器。
服務器端驗證是指用戶把表單數據提交到服務器端,由服務器端對表單數據進行校驗。在服務器端校驗時,若出現錯誤,則會將錯誤信息加入到響應進行返回,待用戶修改后再次提交表單數據,直至通過校驗為止。
- Flask-WTF的FlaskForm類中提供了用于驗證表單數據的validate_on_submit()方法,該方法內部會調用表單驗證器對表單數據進行驗證,具體看如下示例:
(1)app.py創建表單
class RegisterForm(FlaskForm):username = StringField(label='用戶名:', render_kw={'required': False},validators=[DataRequired(message='用戶名不能為空'),Length(3, 15, message='長度應該為3~15')])password = PasswordField('密碼:', render_kw={'required': False},validators=[DataRequired(message='密碼不能為空')])password2 = PasswordField('確認密碼:', render_kw={'required': False},validators=[DataRequired(message='密碼不能為空'),EqualTo('password', message='兩次密碼不一致')])submit = SubmitField('注冊')
(2)通過validate_on_submit()對表單數據進行驗證
validate_on_submit()方法的返回值是一個布爾值,若返回值為True,則表示用戶提交的表單數據符合驗證器定義的規則,說明通過驗證;若返回值為False,則用戶提交的表單數據不符合驗證器定義的規則,說明未通過驗證。
針對未通過驗證的情況,FlaskForm會將錯誤消息添加到表單類的errors屬性中,errors屬性的值是一個匹配表單字段類屬性到錯誤信息列表的字典。若需要獲取具體的錯誤信息列表,則可以在模板文件中通過“form.字段名. errors”進行獲取。
app = Flask(__name__)
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():form = RegisterForm()if form.validate_on_submit():return '注冊成功!'return render_template('register_verification.html', form=form)
if __name__ == '__main__':app.run()
(3) 在templates文件夾中創建模板文件register.html,并在該模板文件中獲取表單字段
<form method="post">{# 定義宏循環遍歷錯誤信息列表#}{% macro print_error(form_fields) %}{% for error_message in form_fields %}<p class="error" style="color: red;display:inline;" >{{ error_message }}</p>{% endfor %}{% endmacro %}<span>{{ form.username.label }}</span><br>{{ form.username }}{{ print_error(form.username.errors) }}<br><span>{{ form.password.label }}</span><br>{{ form.password }}{{ print_error(form.password.errors) }}<br><span>{{ form.password2.label }}</span><br>{{ form.password2 }}{{ print_error(form.password2.errors) }}<br><p>{{ form.submit }}</p></form>