下面咱们来编写全部表单类,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属性。