Day03 Web表單

源代碼: 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驗證函數

驗證函數 說明
Email 驗證電子郵件地址
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()的要求是,框框中的內容不為空才可以提交。
如果你什么都沒寫,然后提交,就會出現:


類似這樣的情況。具體看每個人電腦的具體實現了。
還有一點,表單的提交要通過POST方法,這里不再多余說了,具體去看HTTP協議。

但是這個頁面還是有問題的,當你按下F5去刷新頁面的時候,會給你個提示:問你表單是不是要重新提交一下。
因為頁面刷新會向瀏覽器重新發送最后一個請求,這里的請求是提交表達,基于這個原因,我們利用重定向,來改成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中。怎么理解呢?
瀏覽器是一個傻子,他只能記住最后發生的一件事情,這個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 %}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容