Flask 擴展 表單

pip install flask-wtfhtml

一個簡單的表單

from flask_wtf import Form
from wtforms import StringField
from wtforms.validators import DataRequired
 
class MyForm(Form):
    user = StringField('Username', validators=[DataRequired()])

表單類MyForm定義個了一個字符型字段,也就是一個文字輸入框」user」。StringField的第一個參數」Username」指定了該字段的顯示名,第二個參數指定了驗證規則。這是一個列表,也就是你能夠對一個字段定義多個驗證規則,上例中咱們使用了」wtforms.validators.DataRequired」驗證,也就是表明了該字段爲必填項,表單提交時必須非空。正則表達式

下一步,咱們寫個視圖函數login來使用MyForm表單flask

from flask import Flask, render_template
app = Flask(__name__)
app.secret_key = '1234567'
 
@app.route('/login', methods=('GET', 'POST'))
def login():
    form = MyForm()
    if form.validate_on_submit():
        # if form.user.data == 'admin':
        if form.data['user'] == 'admin':
            return 'Admin login successfully!'
        else:
            return 'Wrong user!'
    return render_template('login.html', form=form)

有了這個」form.validate_on_submit()」方法,咱們就不用像以前同樣經過請求方法是否爲」POST」來判斷表單是否提交。在表單提交後,咱們能夠用表單對象的data屬性來獲取提交內容,這個」form.data」是一個字典類型。上例中,它只有一個字段,也就是」user」。咱們一樣也能夠用」form.user.data」獲取」user」字段的值。在非提交狀態下,咱們就渲染模板,而且往模板中傳入表單對象。另外注意,這裏要設置」app.secret_key」,由於表單類中會使用到會話對象session。瀏覽器

最後讓咱們寫」login.html」模板來顯示這個表單:安全

<form method="POST" action="{{ url_for('login') }}">
    {{ form.hidden_tag() }}
    {{ form.user.label }}: {{ form.user(size=20) }}
    <input type="submit" value="Submit">
</form>

表單中,」form.hidden_tag()」會生成一個隱藏的」<div>」標籤,其中會渲染任何隱藏的字段,最主要的是CSRF字段。這個CSRF(Cross-Site Request Forgery跨站請求僞造)是一種經過假裝來自受信任用戶的請求,來發送惡意攻擊的方法,具體內容你們能夠在網上搜到。WTForms默認開啓CSRF保護,若是你想關閉它(建議不要這樣作),能夠在實例化表單時傳入參數,好比」form = MyForm(csrf_enabled=False)」。babel

「form.user.label」會輸出」user」字段的顯示名,即上例中的」Username」;」form.user」會輸出一個」text」類型的」<input>」標籤,它的參數」size=20″會成爲這個」<input>」標籤裏的屬性。因此上面的模板內容在渲染後,會被轉換爲下面這段HTML代碼:session

<form method="POST" action="/login">
    <div style="display:none;"><input id="csrf_token" name="csrf_token" type="hidden" value="1458707165##33a1f1384d3c12dca29cce5e8ccf6e4d21f5f28f"></div>
    <label for="user">Username</label>: <input id="user" name="user" size="20" type="text" value="">
    <input type="submit" value="Submit">
</form>

運行返回以下結果app

當咱們輸入」admin」時,返回成功;輸入其餘字符串時,返回失敗;而不輸入直接提交,會返回表單頁函數

表單字段類型

WTForms提供了大量內置的字段類型,來便於咱們建立表單項,它們都放在」wtforms.fields」包下。下面,咱們建立一個用戶註冊表單類,並將經常使用的字段類型都包括在其中,爲了方便理解,描述就直接寫在註釋裏:ui

from wtforms.fields import (StringField, PasswordField, DateField, BooleanField,
                            SelectField, SelectMultipleField, TextAreaField,
                            RadioField, IntegerField, DecimalField, SubmitField)
from wtforms.validators import DataRequired, Length, Email, EqualTo, NumberRange
 
class RegisterForm(Form):
    # Text Field類型,文本輸入框,必填,用戶名長度爲4到25之間
    username = StringField('Username', validators=[Length(min=4, max=25)])
 
    # Text Field類型,文本輸入框,Email格式
    email = StringField('Email Address', validators=[Email()])
 
    # Text Field類型,密碼輸入框,必填,必須同confirm字段一致
    password = PasswordField('Password', [
        DataRequired(),
        EqualTo('confirm', message='Passwords must match')
    ])
 
    # Text Field類型,密碼輸入框
    confirm = PasswordField('Repeat Password')
 
    # Text Field類型,文本輸入框,必須輸入整型數值,範圍在16到70之間
    age = IntegerField('Age', validators=[NumberRange(min=16, max=70)])
 
    # Text Field類型,文本輸入框,必須輸入數值,顯示時保留一位小數
    height = DecimalField('Height (Centimeter)', places=1)
 
    # Text Field類型,文本輸入框,必須輸入是"年-月-日"格式的日期
    birthday = DateField('Birthday', format='%Y-%m-%d')
 
    # Radio Box類型,單選框,choices裏的內容會在ul標籤裏,裏面每一個項是(值,顯示名)對
    gender = RadioField('Gender', choices=[('m', 'Male'), ('f', 'Female')],
                                  validators=[DataRequired()])
 
    # Select類型,下拉單選框,choices裏的內容會在Option裏,裏面每一個項是(值,顯示名)對
    job = SelectField('Job', choices=[
        ('teacher', 'Teacher'),
        ('doctor', 'Doctor'),
        ('engineer', 'Engineer'),
        ('lawyer', 'Lawyer')
    ])
 
    # Select類型,多選框,choices裏的內容會在Option裏,裏面每一個項是(值,顯示名)對
    hobby = SelectMultipleField('Hobby', choices=[
        ('swim', 'Swimming'),
        ('skate', 'Skating'),
        ('hike', 'Hiking')
    ])
 
    # Text Area類型,段落輸入框
    description = TextAreaField('Introduction of yourself')
 
    # Checkbox類型,加上default='checked'即默認是選上的
    accept_terms = BooleanField('I accept the Terms of Use', default='checked',
                                validators=[DataRequired()])
 
    # Submit按鈕
    submit = SubmitField('Register')

每一個字段類型的第一個參數都是顯示名,並且都接收」validator」參數來傳入驗證規則。上例的表單字段上,咱們用到了不少驗證規則,關於這部分,咱們會在下一小節介紹。對於時間日期字段,如」DateField」或」DateTimeField」,它們都有一個」format」參數來傳入可識別的日期格式;對於選擇框,如」RadioField」, 「SelectField」或」SelectMultipleField」,它們都有一個」choices」參數來傳入可選擇項,每一個項是一個」(值, 顯示名稱)」對,同時它們也有一個參數」coerce」參數來強制轉換選擇項值的類型,好比」coerce=int」。

接下來,讓咱們編寫模板,由於字段比較多,咱們先寫一個宏來渲染單個字段,並存放在模板文件」_field.html」中:

{% macro render_field(field) %}
<tr>
  <td>{{ field.label }}</td>
  <td>{{ field(**kwargs)|safe }}</td>
  <td>{% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </td>
</tr>
{% endmacro %}

這個」render_field」宏用來渲染表格中的一個行,它有三個列,分別是字段顯示名,字段值,和錯誤信息(若是有錯誤的話)。而後,咱們寫」register.html」模板:

<!doctype html>
<title>Registration Form Sample</title>
<h1>User Registration</h1>
{% from "_field.html" import render_field %}
<form method="POST" action="{{ url_for('register') }}">
  {{ form.hidden_tag() }}
  <table>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.age) }}
    {{ render_field(form.height) }}
    {{ render_field(form.gender) }}
    {{ render_field(form.birthday) }}
    {{ render_field(form.job) }}
    {{ render_field(form.hobby) }}
    {{ render_field(form.description) }}
    {{ render_field(form.accept_terms) }}
  </table>
  {{ form.submit }}
</form>

模板中導入」render_field」宏,並依次渲染用戶註冊表單裏的每個字段。最後,咱們寫個視圖函數來顯示這個表單:

@app.route('/register', methods=('GET', 'POST'))
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        flash('User "%s" registered successfully! Please login.' % form.username.data)
        login_form = LoginForm()
        return render_template('login.html', form=login_form)
 
    return render_template('register.html', form=form)

打開瀏覽器,訪問」/register」地址,你會看到這樣的表單頁面:

若是你什麼都不輸入,直接提交,錯誤信息將會在字段旁顯示:

這個頁面還很醜陋,你能夠經過CSS來美化它,本文就不介紹了。總之,你們已經被WTForms的強大感染到了吧!

驗證規則

上一節的例子中其實已經把大部分經常使用的驗證規則validator都用上了,WTForms一樣提供了大量內置的驗證規則,它們都放在」wtforms.validators」包下。這裏咱們就來列舉一下:

驗證規則 說明
DataRequired 驗證必填項
Email 驗證郵件地址格式
EqualTo 驗證必須同另外一個字段值相同,它需傳入另外一個字段的名稱」fieldname」
Length 驗證輸入字符串長度,它有兩個參數:」min」最小長度,」max」最大長度,缺省的話就不檢查
NumberRange 驗證輸入數值的範圍,它有兩個參數:」min」最小值,」max」最大值,缺省的話就不檢查
URL 驗證URL格式
IPAddress 驗證IP地址格式,默認IPV4,你能夠傳入」ipv6=True」來驗證IPV6地址
MacAddress 驗證Mac地址格式
AnyOf 傳入一個列表做爲參數,驗證是否匹配列表中的任一值
NoneOf 傳入一個列表做爲參數,驗證是否與列表中的全部值都不一樣
Regexp 正則表達式驗證,需傳入一個正則表達式,它還有一個flags參數,若是你傳入」re.IGNORECASE」,就會忽略大小寫

全部的validator都有一個」message」參數,用來指定當驗證失敗時拋出的錯誤消息,不指定的話WTForms就會使用默認錯誤消息。

文件上傳

WTForms自己有一個」FileField」用來處理文件上傳功能,Flask-WTF擴展對其做了封裝,使得咱們能夠更方便的在Flask應用中實現文件上傳。如今就讓咱們來定義一個文件上傳的表單類:

from flask_wtf.file import FileField, FileAllowed, FileRequired
 
class AttachForm(Form):
    attach = FileField('Your Attachment', validators=[
        FileRequired(),
        FileAllowed(['jpg', 'png'], 'Images only!')
    ])

咱們引入」flask_wtf.file」包下的文件上傳框」FileField」,和兩個驗證規則」FileRequired」及」FileAllowed」。」FileRequired」驗證表單提交時必須有文件已被指定;」FileAllowed」驗證文件的類型,上例中只接收以」jpg」和」png」爲後綴的文件,若是不是會拋出錯誤消息」Images only!」。

模板文件很簡單,只要記得在」<form>」標籤里加上屬性’enctype=」multipart/form-data」‘便可:

<form method="POST" action="{{ url_for('upload') }}" enctype="multipart/form-data">
    {{ form.hidden_tag() }}
    {{ form.attach.label }} {{ form.attach }}
    <input type="submit" value="Submit">
</form>

最後,寫上視圖函數:

from werkzeug import secure_filename
 
@app.route('/upload', methods=('GET', 'POST'))
def upload():
    form = AttachForm()
    if form.validate_on_submit():
        filename = secure_filename(form.attach.data.filename)
        form.attach.data.save('uploads/' + filename)
        return 'Upload successfully!'

「secure_filename」用來確保文件名安全,咱們在介紹Flask文件和流時有提到過。」form.attach.data」就能夠獲取文件的內容,它的」save()」方法能夠將內容保存到本地文件中去。上例中,咱們把文件保存在本地當前目錄下的」uploads」子目錄中。運行下這段程序,你將看到下圖這樣的表單,你能夠試着上傳一個文件。

表單字段國際化

因爲表單類是在Flask上下文環境外定義的,對於其字段顯示名的國際化,要使用」lazy_gettext」方法。好比:

from flask_wtf import Form
from flask_babel import lazy_gettext
from wtforms import StringField
from wtforms.validators import DataRequired
 
class MyForm(Form):
    user = StringField(lazy_gettext(u'Username'), validators=[DataRequired()])

從Flask-WTF版本0.13開始,」flask_wtf.Form」類被標爲」過期」了,取而代之的是」flask_wtf.FlaskForm」類。你們只須要將上面使用到Form的例子都改成FlaskForm就好了。

相關文章
相關標籤/搜索