在模板中渲染表單
為了能夠在模板中渲染表單,我們需要把表單類實例傳入模板。首先在視圖函數里實例化表單類LoginForm,然后再render_template()函數中使用關鍵腦子參數form將表單實例傳入模板,例如:form/app.py
#傳入表單類實例 from forms import LoginForm @app.route('/basic') def basic(): form=LoginForm() return render_template('login.html',form=form)
在模板中,需要調用表單類的屬性即可獲取字段對應的HTML代碼,如果需要傳入參數,也可以添加括號,如form/templates/basic.html:在模板中渲染表單
<form method="post"> {{ form.csrf_token }}<!-- 渲染CSRF令牌隱藏字段 --> {{ form.username.label }}{{ form.username }}<br> {{ form.password.label }}{{ form.password }}<br> {{ form.remember }}{{ form.remember.label }}<br> {{ form.submit }}<br> </form>
在上面的代碼中,除了渲染各個字段的標簽和字段本身,還調用了form.csrf_token屬性渲染Flask-WTF為表單類自動創建的CSRF令牌字段。form.csrf_token字段包含了自動生成的CSRF令牌值,在提交表單后會自動被驗證,為了確保表單通過驗證,我們必須在表單中手動渲染這個字段。
Flask_WTF為表單類實例提供了一個form.hidden_tag()方法,這個方法會依次渲染表單中所有的隱藏字段。因為csrf_token字段也是隱藏字段,所有當這個方法被調用時也會渲染csrf_token字段。
渲染后獲得的實際HTML代碼如下:
<form method="post"> <input id="csrf_token" name="csrf_token" type="hidden" value="ImE1M2QxNDEyNDA2YTE5NGI3NmU1NGY1M2U2ZDkxNjQ2NDc5NTI3ZjYi.XH0xaQ.RvNFnjwMfAiUyiv58pU2xJkQ42g"><!-- 渲染CSRF令牌隱藏字段 --> <label for="username">Username</label><input id="username" name="username" required type="text" value=""><br> <label for="password">Password</label><input id="password" name="password" required type="password" value=""><br> <input id="remember" name="remember" type="checkbox" value="y"><label for="remember">Remember me</label><br> <input id="submit" name="submit" type="submit" value="Log in"><br> </form>
運行該程序,訪問127.0.0.1:5000/basic可以看到渲染后的表單,頁面中的表單和我們在上面使用HTML編寫的表單相同
在前面介紹過,使用render_kw字典或是在調用字段時傳入參數來定義字段的額外HTML屬性,可以通過這種方式添加CSS類,我們編寫一個Bootstrap風格的表單:
form/templates/bootstrap.html
{% extends 'base.html' %} {% block styles %} <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> {% endblock %} {% block content %} <h1 class="display-4">Bootstrap Style Form</h1> <form method="post"> {{ form.csrf_token }} <div class="form-group"> {{ form.username.label }} {{ form.username(class='form-control') }} </div> <div class="form-group"> {{ form.password.label }} {{ form.password(class='form-contrl') }} </div> <div class="form-check"> {{ form.remember(class='form-check-input') }} {{ form.remember.label }} </div> {{ form.submit(class='btn btn-primary') }} <form/> {% endblock content %}
頁面上訪問127.0.0.1:5000/bootstrap
base.html:
<!DOCTYPE html> <html lang="en"> <head> {% block head %} {% block metas %} <meta charset="utf-8"> {% endblock metas %} <title> {% block title %} Form - HelloFlask {% endblock title %} </title> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='favicon.ico') }}"> {% block styles %} <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}"> {% endblock styles %} {% endblock head %} </head> <body> <nav> {% block nav %} <ul> <li><a href="{{ url_for('basic') }}">Home</a></li> </ul> {% endblock %} </nav> <main> {% for message in get_flashed_messages() %} <div class="alert"> {{ message }} </div> {% endfor %} {% block content %}{% endblock %} </main> <footer> {% block footer %} <small> © 2019 <a href="https://www.cnblogs.com/xiaxiaoxu/" title="xiaxiaoxu's blog">夏曉旭的博客</a> / <a href="https://github.com/xiaxiaoxu/hybridDrivenTestFramework" title="Contact me on GitHub">GitHub</a> / <a href="http://helloflask.com" title="A HelloFlask project">Learning from GreyLi's HelloFlask</a> </small> {% endblock %} </footer> {% block scripts %}{% endblock %} </body> </html>
style.css文件:
body{ margin:auto; width:750px; } img{ max-width:710px; } nav ul{ list-style-type:none; margin:0; padding:0; overflow:hidden; background-color:#333; } nav li{ float:left; } nav li.a{ display:block; color:white; text-align:center; padding:14px 16px; text-decoration:none; } h1{ color:red; text-align:center; padding:14px 16px; text-decoration:none; } label{width:200px;display:inline-block;} nav li a:hover{ background-color:#111; } main{ padding:10px 20px; } footer{ font-size:13px; color:#888; border-top:1px solid #666; margin-top:25px; text-align:center; padding:10px; } .alert{ position:relative; padding:0.75rem 1.25rem; margin-bottom:1rem; border:1px solid #b8daff; border-radius:0.25rem; color:#004085; background-color: #cce5ff; } .error{ color:red; }
app.py:
#encoding=utf-8 from flask import Flask,render_template,flash,redirect,url_for,session import os app = Flask(__name__) app.secret_key = os.getenv('SECRET_KEY','secret string') @app.route('/html',methods=['GET','POST']) def html(): return render_template('pure_html.html') from forms import LoginForm #傳入表單類實例 @app.route('/basic') def basic(): form=LoginForm() return render_template('basic.html',form=form) @app.route('/bootstrap',methods=['GET','POST']) def bootstrap(): form = LoginForm() if form.validate_on_submit(): username = form.username.data flash('welcome home,%s!'% username) return redirect(url_for('basic')) return render_template('bootstrap.html', form=form) if __name__ == '__main__': app.run(debug=True)
forms.py:
#encoding=utf-8 from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, BooleanField, SubmitField from wtforms.validators import DataRequired, Length class LoginForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired(), Length(8, 128)]) remember = BooleanField('Remember me') submit = SubmitField('Log in') from flask import Flask,render_template,flash,redirect,url_for,session import os app = Flask(__name__) app.secret_key = os.getenv('SECRET_KEY','secret string') if __name__ == '__main__': app.run(debug=True)
如果想手動編寫HTML表單的代碼,需要注意表單字段的name屬性值必須和表單類的字段名稱相同,這樣在提交表單時WTForms才能正確地獲取數據並進行驗證。