下面咱們來編寫全部表單類,personalBlog中主要包含下面這些表單:數據庫
登陸表單;flask
文章表單;app
評論表單;函數
博客設置表單;ui
這裏僅介紹登陸表單、文章表單、分類表單和評論表單,其餘的表單在實現上基本相同。spa
刪除資源也須要使用表單來實現,這裏之因此沒有建立表單類,是由於後面咱們會介紹在實現刪除操做時爲表單實現CSRF保護的更方便的作法。code
用於登陸的LoginForm表單類的實現以下所示:orm
personalBlog/forms.py: 登陸表單csrf
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField, BooleanField from wtforms.validators import DataRequired class LoginForm(FlaskForm): username = StringField('Username', validators=[DataRequired(), Length(1, 20)]) password = PasswordField('Password', validators=[DataRequired(), Length(8, 128)]) remember = BooleanField('Remember me') submit = SubmitField('Log in')
登陸表單由用戶名字段(username)、密碼字段(password)、「記住我」複選框(remember)和「提交」按鈕(submit)組成。其中使用了兩個新字段: 一個是表示<input type=」password」>的密碼字段PasswordField,它會使用黑色原點來表示密碼;另外一個是表示<input type=」checkbox」>的複選框字段BooleanField,它會返回布爾值做爲數據。blog
用於建立文章的PostForm表單類的實現以下所示:
personalBlog/forms.py: 文章表單
from flask_ckeditor import CKEditorField from wtforms import SelectField from wtforms.validators import DataRequired, Length from personalBlog.models import Category class PostForm(FlaskForm): title = StringField('Title', validators=[DataRequired(), Length(1, 60)]) category = SelectField('Category', coerce=int, default=1) body = CKEditorField('Body', validators=[DataRequired()]) submit = SubmitField() def __init__(self, *args, **kwargs): super(PostForm, self).__init__(*args, **kwargs) self.category.choices = [(category.id, category.name) for category in Category.query.order_by(Category.name).all()]
文章建立表單由標題字段(title)、分類選擇字段(category)、正文字段(body)和「提交」按鈕組成,其中正文字段使用Flask-CKEditor提供的CKEditorField字段。
下拉列表字段使用WTForms提供的SelectField類來表示HTML中的<select>標籤。下拉列表的選項(即<option>標籤)經過參數choices指定。choices必須是一個包含量元素元祖的列表,列表中的元祖分別包含選項值和選項標籤。咱們使用分類的id做爲選項值,分類的名稱做爲選項標籤,這兩個值經過迭代Category.query.order_by(Category.name).all()返回的分類記錄實現。選擇值摩恩爲字符串類型,咱們使用coerce關鍵字指定數據類型爲整形。default用來設置默認的選項值,咱們將其指定爲1,即默認分類的id。
由於Flask-SQLAlchemy依賴於程序上下文才能正常工做(內部使用current_app獲取配置信息),因此這個查詢調用要放到構造方法中執行,在構造方法中對self.category.choices賦值的效果和在類中實例化SelectField類並設置choices參數相同。
用於建立分類的CategoryForm表單類的實現以下所示:
personalBlog/forms.py: 分類建立表單
from wtforms.validators import DataRequired from wtforms import ValidationError from personalBlog.models import Category class CatetoryForm(FlaskForm): name = StringField('Name', validators = [DataRequired(), Length(1, 30)]) submit = SubmitField() def validate_name(self, field): if Category.query.filter_by(name = field.data).first(): raise ValidationError('Name already in use.')
分類建立字段僅包含分類名稱字段(name)和提交字段。分類的名稱要求不能重複,爲了不寫入重複的分類名稱致使數據庫出錯,咱們在CategoryForm類中添加了一個validate_name方法,做爲name字段的自定義行內驗證器,它將在驗證name字段時和其餘驗證函數一塊兒調用。在這個驗證方法中,咱們使用字段的值(field.data)做爲name列的參數值進行查詢,若是查詢到已經存在同名記錄,那麼久爆出ValidationError異常,傳遞錯誤消息做爲參數。
用於建立評論的CommentForm表單類的實現以下所示:
personalBlog/forms.py: 評論表單
from wtforms import TextAreaField from wtforms.validators import Email, URL, Length, Optional class CommentForm(FlaskForm): author = StringField('Name', validators = [DataRequired(), Length(1, 30)]) email = StringField('Email', validators = [DataRequired(), Email(), Length(1, 254)]) site = StringField('Site', validators = [Optional(), URL(), Length(0, 255)]) body = TextAreaField('Comment', validators = [DataRequired()]) submit = SubmitField()
在這個表單中,email字段使用了用於驗證電子郵箱地址的Email驗證器。另外,由於評論者的站點是能夠留空的字段,因此咱們使用Optional驗證器來使字段能夠爲空。site字段使用URL驗證器確保輸入的數據爲有效的URL。
由於site字段能夠爲空,因此一併附加的Length驗證器的最小長度須要設爲0。
和匿名用戶的表單不一樣,管理員不須要填寫諸如姓名、電子郵箱等字段。咱們單獨爲管理員建立了一個表單類,這個表單類繼承自CommentForm類,以下所示:
personalBlog/forms.py:管理員的評論表單
from wtforms import HiddenField class AdminCommentForm(CommentForm): author = HiddenField() email = HiddenField() site = HiddenField()
在這個表單中,姓名、Email、站點字段使用HiddenField類從新定義。這個類型表明隱藏字段,即HTML中的<input type=」hidden」>。
在模板中手動渲染表單時,咱們可使用Flask-WTF爲表單添加的hidden_tag()方法來渲染全部隱藏字段,而不用逐個調用三個屬性。另外,hidden_tag()方法會一併渲染CSRF令牌字段,所以不用在手動調用csrf_token屬性。