儘管 Flask 的請求對象提供的信息足夠用於處理 Web 表單,但有些任務很單調,並且要重複操做。好比,生成表單的 HTML 代碼和驗證提交的表單數據。html
Flask-WTF(http://pythonhosted.org/Flask-WTF/)擴展能夠把處理 Web 表單的過程變成一種愉悅的體驗。這個擴展對獨立的 WTForms(http://wtforms.simplecodes.com)包進行了包裝,方便集成到 Flask 程序中。python
默認狀況下,Flask-WTF 能保護全部表單免受跨站請求僞造(Cross-Site Request Forgery,CSRF)的攻擊。惡意網站把請求發送到被攻擊者已登陸的其餘網站時就會引起 CSRF 攻擊。爲了實現 CSRF 保護,Flask-WTF 須要程序設置一個密鑰。Flask-WTF 使用這個密鑰生成加密令牌,再用令牌驗證請求中表單數據的真僞。正則表達式
from flask import Flask app = Flask(__name__) app.config[SECRET_KEY] = 'aaaaaaaaaaaa'
app.config 字典可用來存儲框架、擴展和程序自己的配置變量。使用標準的字典句法就能把配置值添加到 app.config 對象中。這個對象還提供了一些方法,能夠從文件或環境中導入配置值。
SECRET_KEY 配置變量是通用密鑰,可在 Flask 和多個第三方擴展中使用。如其名所示,加密的強度取決於變量值的機密程度。不一樣的程序要使用不一樣的密鑰,並且要保證其餘人不知道你所用的字符串。flask
建立forms.pybootstrap
from flask_wtf import FlaskForm from wtforms import BooleanField, StringField, SelectField, RadioField, FileField, PasswordField, SubmitField from wtforms.validators import Email, EqualTo, DataRequired, ValidationError, Length, Regexp from app import db from app.models import User class LoginForm(FlaskForm): """用戶登陸表單""" username = StringField( label='用戶名', validators=[ DataRequired('用戶名不能爲空') ], description='用戶名', render_kw={ 'placeholder':'請輸入用戶名' } ) password = PasswordField( label="密碼", validators=[ DataRequired('密碼不能爲空') ], description='密碼', render_kw={ 'placeholder':'請輸入密碼' } ) submit = SubmitField( "登陸" ) def validate_username(self, field): username = field.data user = User.query.filter_by(username=username).count() if user == 0: raise ValidationError('用戶名不正確') class RegisterForm(FlaskForm): username = StringField( label='用戶名', validators=[ DataRequired('用戶名不能爲空'), Length(5,20, '長度在5~20之間'), ], description='用戶名', render_kw={ 'placeholder':'請輸入用戶名' } ) email = StringField( label='郵箱', validators=[ DataRequired('不能爲空'), Email('請輸入正確的格式') ], description='郵箱' ) password = PasswordField( label='密碼', validators=[ DataRequired('不能爲空'), ], ) repassword = PasswordField( label='密碼', validators=[ DataRequired('不能爲空'), EqualTo('password','兩次密碼不一致') ] ) submit = SubmitField( '註冊' ) def validate_username(self, field): """驗證用戶是否重複""" username = field.data user_count = User.query.filter_by(username=username).count() if user_count >= 1: raise ValidationError('用戶名重複') def validate_email(self, filed): """驗證郵箱是否註冊""" email = filed.data user_count = User.query.filter_by(email=email).count() if user_count >= 1: raise ValidationError('郵箱已經註冊')
WTForms支持的HTML標準字段
|字段類型|說明|
|---|---|
|StringField | 文本字段|
|TextAreaField |多行文本字段|
|PasswordField | 密碼文本字段|
|HiddenField | 隱藏文本字段|
|DateField | 文本字段,值爲 datetime.date 格式|
|DateTimeField |文本字段,值爲 datetime.datetime 格式|
|IntegerField | 文本字段,值爲整數|
|DecimalField |文本字段,值爲 decimal.Decimal|
|FloatField | 文本字段,值爲浮點數|
|BooleanField |複選框,值爲 True 和 False|
|RadioField |一組單選框|
|SelectField | 下拉列表|
|SelectMultipleField | 下拉列表,可選擇多個值|
|FileField | 文件上傳字段|
|SubmitField | 表單提交按鈕|
|FormField | 把表單做爲字段嵌入另外一個表單|
|FieldList | 一組指定類型的字段|跨域
WTForms驗證函數
|驗證函數|說明|
|---|---|
|Email | 驗證電子郵件地址|
|EqualTo |比較兩個字段的值;經常使用於要求輸入兩次密碼進行確認的狀況|
|IPAddress | 驗證 IPv4 網絡地址|
|Length | 驗證輸入字符串的長度|
|NumberRange | 驗證輸入的值在數字範圍內|
|Optional | 無輸入值時跳過其餘驗證函數|
|Required | 確保字段中有數據|
|Regexp | 使用正則表達式驗證輸入值|
|URL | 驗證 URL|
|AnyOf | 確保輸入值在可選值列表中|
|NoneOf | 確保輸入值不在可選值列表中|網絡
@home.route('/login', methods=['GET', 'POST']) def login(): """登陸""" form = LoginForm() if form.validate_on_submit(): data = form.data user = User.query.filter_by(username=data['username']).first() if check_password_hash(user.password, data['password']): print(222222) login_user(user) print(1111) return redirect(url_for('home.index')) else: print(44444444) flash('登陸失敗','err') return render_template('/home/user/login.html', form=form)
例經過參數 form 傳入模板,在模板中能夠生成一個簡單的表單,以下所示:app
<form method="POST"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name() }} {{ form.submit() }} </form>
即使能指定 HTML 屬性,但按照這種方式渲染表單的工做量仍是很大,因此在條件容許的狀況下最好能使用 Bootstrap 中的表單樣式。Flask-Bootstrap 提供了一個很是高端的輔助函數,可使用 Bootstrap 中預先定義好的表單樣式渲染整個 Flask-WTF 表單,而這些操做只需一次調用便可完成。使用 Flask-Bootstrap,上述表單可以使用下面的方式渲染:框架
{% import "bootstrap/wtf.html" as wtf %} {{ wtf.quick_form(form) }}
import 指令的使用方法和普通 Python 代碼同樣,容許導入模板中的元素並用在多個模板中。導入的 bootstrap/wtf.html 文件中定義了一個使用 Bootstrap 渲染 Falsk-WTF 表單對象的輔助函數。wtf.quick_form() 函數的參數爲 Flask-WTF 表單對象,使用 Bootstrap 的默認樣式渲染傳入的表單。hello.py 的完整模板如示例 4-3 所示。
templates/index.html:使用 Flask-WTF 和 Flask-Bootstrap 渲染表單函數
{% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class="page-header"> <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1> </div> {{ wtf.quick_form(form) }} {% endblock %}
模板的內容區如今有兩部分。第一部分是頁面頭部,顯示歡迎消息。這裏用到了一個模板條件語句。Jinja2 中的條件語句格式爲 {% if condition %}...{% else %}...{% endif %}。若是條件的計算結果爲 True,那麼渲染 if 和 else 指令之間的值。若是條件的計算結果爲 False,則渲染 else 和 endif 指令之間的值。在這個例子中,若是沒有定義模板變量 name,則會渲染字符串「Hello, Stranger!」。內容區的第二部分使用 wtf.quick_form() 函數渲染NameForm 對象。