使用Flask-WTF製做一個帶驗證碼的登錄表單

Flask-WTF遇到的坑

在使用Flask-WTF的時候,使用qucik_form()快速生成表單的確是很爽,可是生成的表單的樣式並非想要的,這個時候就不能使用qucik_form()了。html

PS:目前還不是很熟悉Flask-WTF的驗證表單的原理,好比Require()驗證應該是用JS,EqualTo這種就是放在後端處理的。有時間了須要好好讀一讀官方文檔。前端

froms.py中定義了以下的Register表單:python

class RegisterForm(Form):
    """註冊表單"""

    username = StringField(u'暱稱', validators=[Required()])
    email = StringField(u'郵箱', validators=[Required(), Email()])
    password = PasswordField(u'密碼', validators=[Required(), Length(6, 12, message=u'密碼長度在6到12爲')])
    password1 = PasswordField(u'確認密碼', validators=[Required(), Length(6, 12, message=u'密碼長度在6到12爲'), EqualTo('password', message=u'密碼必須一致')])
    verification_code = StringField(u'驗證碼', validators=[Required(), Length(4, 4, message=u'填寫4位驗證碼')])
    submit = SubmitField(u'註冊')

verification_code字段中,須要加載驗證碼圖片,此時在模板中使用qucik_form()就很難處理了。後端

此時就須要手動控制表單的生成。session

自定義生成表單

在模板中,手動渲染很麻煩:post

<form action="" method="post" class="form" role="form">
        {{ form.hidden_tag() }}
        <div class="form-group required">
            {{ form.username.label(class="control-label") | safe }}
            {{ form.username(class="form-control", required=True) }}
        </div>
        <div class="form-group required">
            {{ form.email.label(class="control-label") | safe }}
            {{ form.email(class="form-control", required=True) }}
        </div>
        {% if form.errors.password %}
        <div class="form-group has-error required">
            {{ form.password.label(class="control-label") | safe }}
            {{ form.password(class="form-control", required=True) }}
            {% for error in form.errors.password %}
                <p class="help-block">{{ error }}</p>
            {% endfor %}
        </div>
        {% else %}
        <div class="form-group required">
            {{ form.password.label(class="control-label") | safe }}
            {{ form.password(class="form-control", required=True) }}
        </div>
        {% endif %}

        {% if form.errors.password1 %}
        <div class="form-group has-error required">
            {{ form.password1.label(class="control-label") | safe }}
            {{ form.password1(class="form-control", required=True) }}
            {% for error in form.errors.password1 %}
                <p class="help-block">{{ error }}</p>
            {% endfor %}
        </div>
        {% else %}
        <div class="form-group required">
            {{ form.password1.label(class="control-label") | safe }}
            {{ form.password1(class="form-control", required=True) }}
        </div>
        {% endif %}

        {% if form.errors.verification_code %}
        <div class="form-group has-error required">
            {{ form.verification_code.label(class="control-label") | safe }}
            {{ form.verification_code(class="form-control", required=True) }}
            {% for error in form.errors.verification_code %}
                <p class="help-block">{{ error }}</p>
            {% endfor %}
        </div>
        {% else %}
        <div class="form-group required">
            {{ form.verification_code.label(class="control-label") | safe }}
            <label class="control-label"><img src="{{ url_for('static', filename='image/code/'+code_img) }}"></label>
            {{ form.verification_code(class="form-control", required=True) }}
        </div>
        {% endif %}

        {{ form.submit(class="btn btn-info submit") }}
    </form>
    <div class="register">
        <a type="button" class="btn btn-info" style="width: 100%;" href="#">已有帳號?登陸</a>
    </div>

下面是在編寫以上代碼時遇到的坑:ui

  1. 在模板中須要處理form.errors。若是表單驗證失敗,失敗的消息保存在form.errors中。url

    若是表單驗證錯誤,沒有處理`form.errors`的話前端就不會有任何提示,給人形成的錯覺就是`validate_on_submit`方法沒有執行。
  2. 不要忘記form.hidden_tag()。這個是加載並隱藏csrf_token。沒有csrf_token,通常會報錯。spa

沒有銀彈
上面的代碼只實現了非空驗證、密碼是否相等驗證、密碼長度驗證等功能,不知道不用Flask-WTF改用HTML + JS實現是否是代碼量差很少。code

生成驗證碼

生成驗證碼使用PIL來生成圖片。廖雪峯有介紹如何生成驗證碼圖片PIL-廖雪峯

views.py中處理表單

處理表單的邏輯:

  1. 每次有請求後,就調用generate_verification_code()返回一個驗證碼圖片的url和驗證碼文本,而後將驗證碼保存在session中。

  2. 每次驗證表單後,驗證表單中輸入的驗證碼時候和session中的一致

  3. 按條件返回模板

代碼以下:

@user.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        username = form.username.data
        print username
        if get_user(username):
            print '帳號已被註冊'
            flash(u'帳號已被註冊')
            code_img, code_text = generate_verification_code()
            session['code_text'] = code_text
            return render_template('user/register.html', form=form, code_img=code_img)
        if 'code_text' in session and session['code_text'] != form.verification_code.data:
            code_img, code_text = generate_verification_code()
            session['code_text'] = code_text
            return render_template('user/register.html', form=form, code_img=code_img)
        email = form.email.data
        password = form.password.data
        user = User(username=username, password=password, email=email)
        try:
            db.session.add(user)
            db.session.commit()
            return redirect(url_for('.index'))
        except:
            print traceback.print_exc()
            db.session.rollback()
            flash(u'註冊失敗')
            code_img, code_text = generate_verification_code()
            session['code_text'] = code_text
            return render_template('user/register.html', form=form, code_img=code_img)
    code_img, code_text = generate_verification_code()
    session['code_text'] = code_text
    return render_template('user/register.html', form=form, code_img=code_img)

將驗證碼保存在圖片中不是一個號辦法,目前也沒有想到如何保存。

最終結果

clipboard.png

相關文章
相關標籤/搜索