表單數據的處理涉及不少內容,從獲取數據到保存數據大體有如下步驟:html
一、 解析請求,獲取表單數據java
二、 對數據進行必要的轉換,好比講勾選框的值轉換成python的布爾值python
三、 驗證數據是否符合要求,同時驗證CSRF令牌。web
四、 若是驗證未經過則須要生成錯誤消息,並在模板中顯示錯誤消息。數據庫
五、 若是驗證經過,就把數據保存到數據庫或作進一步處理flask
使用Flask-WTF和WTForms能夠極大地簡化這些步驟瀏覽器
在HTML中,當<form>標籤聲明的表單中類型爲submit的提交字段被單擊時,就會建立一個表單的HTTP請求,請求中包含表單各個字段的數據。表單的提交行爲主要有三個屬性控制,以下表:安全
form標籤的action屬性用來指定表單被提交的目標URL,默認爲當前URL,就是渲染該模板的路由所在的URL。服務器
當使用get方法提交表單時,表單的數據會以查詢字符串的形式附加在請求的URL裏,如:app
127.0.0.1:5000:/basic?username=xiaxiaoxu&password=12345
GET方式僅適用於長度不超過3000個字符,且不包含敏感信息的表單。由於這種方式會直接將用戶提交的表單數據暴露在URL中,容易被攻擊者截獲,實例中的狀況是危險的。所以到處於安全的考慮,咱們通常使用post方法提交表單。使用post方式時,按照默認的編碼類型,表單數據會存儲在請求主體中,好比:
POST /basic HTTP/1.0
…
Content-Type:application/x-www-form-urlencoded
Content-Length:30
username=xiaxiaoxu&12345
Flask爲路由設置默認的監聽方法是GET,爲了支持接收表單提交發送的POST請求,咱們須要在app.route()裝飾器裏使用methods關鍵字爲路由指定HTTP方法,好比:
@app.route('/',methods=['GET','POST']) def basic(): form=LoginForm() return render_template('basic.html',form=form)
表單的驗證一般分爲如下幾種形式
客戶端驗證是指在客戶端(好比web瀏覽器)對用戶的輸入值進行驗證。好比,使用HTML5內置的驗證屬性便可實現基本的客戶端驗證(type、required、min、max、accept等)。
例如,給username字段添加required標誌:
<input type=」text」 name=」username」 required>
若是用戶沒有輸入內容而按下提交按鈕,會彈出瀏覽器內置的錯誤提示
和其餘附件HTML屬性相同,咱們能夠在定義表單時經過render_kw傳入這些屬性,或是在渲染表單時傳入,像requiredd這類布爾值屬性,值能夠爲空或是任意ASCII字符,如:
{{ form.username(required=’’) }}
除了使用HTML5提供的屬性實現基本的客戶端驗證,咱們一般會使用javaScript實現完善的驗證機制,好比使用javaScript表單驗證庫-jQuery
客戶端方式能夠實時動態提示用戶輸入是否正確,只有用戶輸入正確後纔會將表單數據發送到服務器,客戶端驗證能夠加強用戶體驗,下降服務器負載。
服務器端驗證是指用戶把輸入的數據提交到服務器端,在服務器端對數據進行驗證。若是驗證出錯就會在響應中加入錯誤信息。用戶修改後再提交表單,知道經過驗證。在flask中使用WTForms實現的就是服務器端驗證
WTForms驗證表單字段的方式是在實例化表單類時傳入表單數據,而後對錶單實例調用validate()方法。這會逐個對字段調用字段實例化時定義的驗證器,返回表示驗證結果的布爾值。若是驗證失敗,就把錯誤消息存儲到表單實例的errors屬性對應的字典中,驗證的過程以下所示:
>>> from app import app >>> from flask import request >>> app.test_request_context('/basic').push()#激活請求上下文 >>> from flask import current_app >>> app.app_context().push()#激活程序上下文 >>> current_app.name 'app' >>>#定義LoginForm類 >>> from wtforms import Form, StringField,PasswordField,BooleanField >>> from wtforms.validators import DataRequired,length >>> class LoginForm(Form): ... username = StringField('Username', validators=[DataRequired()]) ... password = PasswordField('Password',validators=[DataRequired(),length(8,128)]) ... >>> form = LoginForm(username='',password='123') >>> form.data #表單數據字典 {'username': '', 'password': '123'} >>> form.validate() False >>> form.errors {'username': [u'This field is required.'], 'password': [u'Field must be between 8 and 128 characters long.']} >>> form2 = LoginForm(username='xiaxiaoxu', password='123456') >>> form2.data #表單數據字典 {'username': 'xiaxiaoxu', 'password': '123456'} >>> form2.validate() False >>> form2.errors #錯誤消息字典 {'password': [u'Field must be between 8 and 128 characters long.']} >>> form3 = LoginForm(username='xiaxiaoxu', password='123456789') >>> form3.data {'username': 'xiaxiaoxu', 'password': '123456789'} >>> form3.validate() True >>> form3.errors {}
由於表單使用POST方法提交,若是單純使用WTForms,在實例化表單時須要首先把request.form傳入表單類(LoginForm(username='',password='123')),而使用Flask-WTF時,表單類繼承的FlaskForm基類默認會從request.form獲取表單數據,因此不須要手動傳入。
使用POST方法提交的表單,其數據會被Flask解析成爲一個字典,能夠經過請求對象的form屬性獲取(request.form);使用GET方法提交的表單的數據一樣會被解析爲字典,不過要經過請求對象的args屬性獲取(request.args)。