源代碼: https://github.com/ltoddy/flask-tutorial
技術交流群:630398887(歡迎一起吹牛)
pip install flask-wtf
先看看一個普通的HTML頁面的表單的樣子:
<form action="">
<label>你叫什么名字:<input type="text"></label><br>
<input type="button" value="提交">
</form>
也就是說阿,在你要填寫的框框前有一個提示的標語(label),然后有一個提交的按鈕绍撞,按鈕上寫著提交倆字。
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import SubmitField
class NameForm(FlaskForm):
name = StringField('你叫什么名字凑懂?') # 這里的'你叫什么名字硬贯?'就是對應的那個提示語
# StringField() 就是那個輸入的框框
submit = SubmitField('提交') # 這里的'提交'對應著按鈕的文字
先大體瀏覽一下下面兩個表格岛马,然后我在具體將使用
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驗證函數
驗證函數 | 說明 |
---|---|
驗證電子郵件地址 | |
EqualTo | 比較兩個字段的值,常用于要求輸入兩次密碼進行確認的情況 |
IPAddress | 驗證IPv4網絡地址 |
Length | 驗證輸入字符串的長度 |
NumberRange | 驗證輸入的值在數字范圍內 |
Optional | 無輸入值時跳過其他驗證函數 |
Required | 確保字段中有數據 |
Regexp | 使用正則表達式驗證輸入值 |
URL | 驗證URL |
AnyOf | 確保輸入值在可選值列表中 |
NoneOf | 確保輸入值不在可選列表中 |
把表單加入到頁面中去:
順便提一句火惊,之前的那個hello_world函數求类,我把它改名為index了。
先看我們的html頁面:
<small>templates/index.html</small>
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block page_content %}
<div class="page-header">
<h1>Hello {% if name %}{{ name }}{% else %}stranger!{% endif %}</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}
第二行:
{% import 'bootstrap/wtf.html' as wtf %}
bootstrap為我們集成好了一個宏(理解成函數就好了)矗晃,它可以很方便的把我們的表單類(剛才的NameForm)渲染成表單仑嗅。
再看下面:
{% <h1>Hello {% if name %}{{ name }}{% else %}stranger!{% endif %}</h1> %}
如果有名字近來,那么顯示名字张症,沒有名字的話就顯示stranger(陌生人)仓技。
再來看一下視圖函數:
<small>blog.py</small>
class NameForm(FlaskForm):
name = StringField('你叫什么名字', validators=[Required()])
submit = SubmitField('提交')
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
name = None
if form.validate_on_submit():
name = form.name.data
form.name.data = ''
return render_template('index.html', name=name, form=form)
注意看,和剛才有差別俗他。
第一個是沒有那個validators=[Required()]這一部分的脖捻,這段是什么意思呢,就是說你在框框中填寫的內容是有要求的兆衅,這個Required()的要求是地沮,框框中的內容不為空才可以提交。
如果你什么都沒寫羡亩,然后提交摩疑,就會出現(xiàn):
類似這樣的情況。具體看每個人電腦的具體實現(xiàn)了畏铆。
還有一點雷袋,表單的提交要通過POST方法,這里不再多余說了辞居,具體去看HTTP協(xié)議楷怒。
但是這個頁面還是有問題的,當你按下F5去刷新頁面的時候瓦灶,會給你個提示:問你表單是不是要重新提交一下鸠删。
因為頁面刷新會向瀏覽器重新發(fā)送最后一個請求,這里的請求是提交表達贼陶,基于這個原因刃泡,我們利用重定向巧娱,來改成GET請求。
<small>blog.py</small>
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html', name=session.get('name', None), form=form)
這里我用到了一個東西:session(會話)捅僵,它會記住上下文家卖,把數據存儲在這個session中。怎么理解呢庙楚?
瀏覽器是一個傻子,他只能記住最后發(fā)生的一件事情趴樱,這個session就是為了強行讓瀏覽器記住一些東西馒闷。
還用到了redirect和url_for這兩個組合,url_for便于我們生成url,當然那一行代碼你也可以寫成:
redirect('/')
因為就是要回到主頁嘛叁征,主頁地址就是'/'纳账,但是隨著程序日益的復雜,你不可能完全掌握所有的地址捺疼,所以我們通過url_for來獲得地址疏虫,url_for('index')注意看括號中的參數內容'index'對應著視圖函數index()的名字。也就是說重新定向到這個函數映射的頁面上啤呼。
看一下完整代碼:
<small>blog.py</small>
from flask import Flask
from flask import render_template
from flask import redirect
from flask import url_for
from flask import session
from flask_bootstrap import Bootstrap
from flask_script import Manager
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import SubmitField
from wtforms.validators import Required
app = Flask(__name__)
app.config['SECRET_KEY'] = 'a string' # 這一行是必須要加上的卧秘,為了防止CRSF攻擊
bootstrap = Bootstrap(app)
manager = Manager(app)
class NameForm(FlaskForm):
name = StringField('你叫什么名字', validators=[Required()])
submit = SubmitField('提交')
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html', name=session.get('name', None), form=form)
@app.route('/<username>')
def user(username):
return render_template('user.html', name=username)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
if __name__ == '__main__':
manager.run()
再介紹一點更人性化的東西:
Flash消息:
有些時候,當你作出了改動的時候官扣,最好有個東西來提醒你:Flash
<small>blog.py</small>
@app.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
old_name = session.get('name')
if old_name is not None and old_name != form.name.data:
flash('你更改了名字')
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('index'))
return render_template('index.html', name=session.get('name', None), form=form)
需要再更改一下我們的模板翅敌,讓flash消息顯示出來
<small>templates/base.html</small>
{% block content %}
{% for message in get_flashed_messages() %}
<div class="alert alert-info">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}