Flask - WTF和WTForms创建表单

一. Flask-WTF

Flask-WTF是集成WTForms,并带有 csrf 令牌的安全表单和全局的 csrf 保护的功能。

每次我们在建立表单所创建的类都是继承与flask_wtf中的FlaskForm,而FlaskForm是继承WTForms中forms。

1.创建基础表单

  1. class LoginForm(FlaskForm):
  2. username = StringField()
  3. password = PasswordField()
  4. remember_me = BooleanField(label='Keep me logged in')

2.CSRF保护

任何使用FlaskForm创建的表单发送请求,都会有CSRF的全部保护,在对应的template中HTML渲染表单时,可以加入form.csrf_token:

  1. <form method="post">
  2. {{ form.csrf_token }}
  3. </form>

但是如果模板中没有表单,则可以使用一个隐藏的input标签加入csrf_token。

  1. <form method="post">
  2. <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
  3. </form>

3.验证表单

在视图处理程序中验证请求:

  1. def login():
  2. form = LoginForm()
  3. if form.validate_on_submit():
  4. return redirect('/success')
  5. return render_template('login.html', form=form)
  6. # 使用validate_on_submit 来检查是否是一个 POST 请求并且请求是否有效。

或者下面这种方式:

  1. new_lf = LoginForm(formdata=request.form)
  2. if new_lf.validate():
  3. return "登陆成功"
  4. else:
  5. return render_template("login.html", lf=new_lf)

4.文件上传

Flask-WTF 提供 FileField 来处理文件上传,它在表单提交后,自动从 flask.request.files 中抽取数据。FileField 的 data 属性是一个 Werkzeug FileStorage 实例。

  1. from werkzeug import secure_filename
  2. from flask_wtf.file import FileField
  3. class PhotoForm(Form):
  4. photo = FileField('Your photo')
  5. @app.route('/upload/', methods=('GET', 'POST'))
  6. def upload():
  7. form = PhotoForm()
  8. if form.validate_on_submit():
  9. filename = secure_filename(form.photo.data.filename)
  10. form.photo.data.save('uploads/' + filename)
  11. else:
  12. filename = None
  13. return render_template('upload.html', form=form, filename=filename)

注意:在 HTML 表单的 enctype 设置成 multipart/form-data,如下:

5.验证码

Flask-WTF 通过 RecaptchaField 也提供对验证码的支持:

  1. rom flask_wtf import Form, RecaptchaField
  2. from wtforms import TextField
  3. class SignupForm(Form):
  4. username = TextField('Username')
  5. recaptcha = RecaptchaField()

还需要配置一下信息:

  1. # 字段 # 配置
  2. RECAPTCHA_PUBLIC_KEY # 必须公钥
  3. RECAPTCHA_PRIVATE_KEY # 必须私钥
  4. RECAPTCHA_API_SERVER # 可选验证码API服务器
  5. RECAPTCHA_PARAMETERS # 可选 一个 JavaScript(api.js)参数的字典
  6. RECAPTCHA_DATA_ATTRS # 可选 一个数据属性项列表 https://developers.google.com/recaptcha/docs/display

二. WTForms

WTForms是一个Flask集成的框架,或者是说库。用于处理浏览器表单提交的数据。它在Flask-WTF 的基础上扩展并添加了一些随手即得的精巧的帮助函数,这些函数将会使在 Flask 里使用表单更加有趣。

1. field字段

WTForms支持HTML字段:

  1. 字段类型: 说明:
  2. StringFidle 文本字段, 相当于type类型为textinput标签
  3. TextAreaField 多行文本字段
  4. PasswordField 密码文本字段
  5. HiddenField 隐藏文本字段
  6. DateField 文本字段, 值为datetime.date格式
  7. DateTimeFieeld 文本字段, 值为datetime.datetime格式
  8. IntegerField 文本字段, 值为整数
  9. DecimalField 文本字段, 值为decimal.Decimal
  10. FloatField 文本字段, 值为浮点数
  11. BooleanField 复选框, 值为True False
  12. RadioField 一组单选框
  13. SelectField 下拉列表
  14. SelectMultipleField 下拉列表, 可选择多个值
  15. FileField 文件上传字段
  16. SubmitField 表单提交按钮
  17. FormFiled 把表单作为字段嵌入另一个表单
  18. FieldList 子组指定类型的字段

2.Validators验证器

WTForms可以支持很多表单的验证函数:

  1. Email
  2. 验证是电子邮件地址
  3. EqualTo
  4. 比较两个字段的值; 常用于要求输入两次密钥进行确认的情况
  5. IPAddress
  6. 验证IPv4网络地址
  7. Length
  8. 验证输入字符串的长度
  9. NumberRange
  10. 验证输入的值在数字范围内
  11. Optional
  12. 无输入值时跳过其它验证函数
  13. DataRequired
  14. 确保字段中有数据
  15. Regexp
  16. 使用正则表达式验证输入值
  17. URL
  18. 验证url
  19. AnyOf
  20. 确保输入值在可选值列表中
  21. NoneOf
  22. 确保输入值不在可选列表中

3.自定义Validators验证器

第一种: in-line validator(内联验证器)

也就是自定义一个验证函数,在定义表单类的时候,在对应的字段中加入该函数进行认证。下面的my_length_check函数就是用于判name字段长度不能超过50.

  1. def my_length_check(form, field):
  2. if len(field.data) > 50:
  3. raise ValidationError('Field must be less than 50 characters')
  4. class MyForm(Form):
  5. name = StringField('Name', [InputRequired(), my_length_check])

第二种:通用且可重用的验证函数

一般是以validate开头,加上下划线再加上对应的field字段(validate_filed),浏览器在提交表单数据时,会自动识别对应字段所有的验证器,然后执行验证器进行判断。

  1. class RegistrationForm(FlaskForm):
  2. email = StringField('Email', validators=[DataRequired(), Length(1, 60), Email()])
  3. username = StringField('Username', validators=[DataRequired(), Length(1, 60),
  4. Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, 'username must have only letters, numbers dots or underscores')])
  5. password = PasswordField('Password', validators=[DataRequired(), EqualTo('password2', message='password must match')])
  6. password2 = PasswordField('Confirm password', validators=[DataRequired()])
  7. def validate_email(self, field):
  8. if User.objects.filter(email=field.data).count() > 0:
  9. raise ValidationError('Email already registered')
  10. def validate_username(self, field):
  11. if User.objects.filter(username=field.data).count() > 0:
  12. raise ValidationError('Username has exist')

第三种:比较高级的validators

  1. class Length(object):
  2. def __init__(self, min=-1, max=-1, message=None):
  3. self.min = min
  4. self.max = max
  5. if not message:
  6. message = u'Field must be between %i and %i characters long.' % (min, max)
  7. self.message = message
  8. def __call__(self, form, field):
  9. l = field.data and len(field.data) or 0
  10. if l < self.min or self.max != -1 and l > self.max:
  11. raise ValidationError(self.message)
  12. length = Length

4.Widget组件

下面可以以登录界面为实例:

login.py

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from flask import Flask, render_template, request, redirect
  4. from wtforms import Form
  5. from wtforms import validators
  6. from wtforms import widgets
  7. class LoginForm(Form):
  8. name = simple.StringField(
  9. label='用户名',
  10. validators=[
  11. validators.DataRequired(message='用户名不能为空.'),
  12. ],
  13. widget=widgets.TextInput(),
  14. render_kw={'class': 'form-control'}
  15. )
  16. pwd = simple.PasswordField(
  17. label='密码',
  18. validators=[
  19. validators.DataRequired(message='密码不能为空.'),
  20. ],
  21. widget=widgets.PasswordInput(),
  22. render_kw={'class': 'form-control'}
  23. )

三. 简单的登录验证表单实例

  1. from flask import Flask, request, render_template, redirect
  2. from wtforms.fields import simple, core
  3. from wtforms import Form, validators
  4. app = Flask(__name__)
  5. app.config["DEBUG"] = True
  6. class LoginForm(Form):
  7. username = simple.StringField(
  8. label="用户名:",
  9. validators=[
  10. validators.DataRequired(message="用户名不能为空"),
  11. validators.Length(min=4, max=10, message="用户名不能小于%(min)d,不能大于%(max)d")
  12. ], # 声明校验方式
  13. id="username",
  14. # widget=widgets.FileInput(),
  15. render_kw={"class": "my_class"},
  16. )
  17. password = simple.PasswordField(
  18. label="密码:",
  19. validators=[
  20. validators.Length(max=10, min=6, message="password不能小于%(min)d,不能大于%(max)d"),
  21. validators.Regexp("\d+", message="密码只能是数字")
  22. ],
  23. id="pwd",
  24. render_kw={"style": "width:300px;"}
  25. )
  26. sub = simple.SubmitField(
  27. label="登陆",
  28. render_kw={"class": "bs"}
  29. )
  30. @app.route("/login", methods=["GET", "POST"])
  31. def login():
  32. if request.method == "GET":
  33. lf = LoginForm()
  34. return render_template("login.html", lf=lf)
  35. else:
  36. new_lf = LoginForm(formdata=request.form)
  37. if new_lf.validate():
  38. return "登陆成功"
  39. else:
  40. return render_template("login.html", lf=new_lf)
  41. class RegForm(Form):
  42. username = simple.StringField(
  43. label="用户名:",
  44. validators=[
  45. validators.Length(min=4, max=10, message="用户名不能小于%(min)d,不能大于%(max)d")
  46. ]
  47. )
  48. password = simple.PasswordField(
  49. label="密码:",
  50. validators=[
  51. validators.Length(max=10, min=6, message="password不能小于%(min)d,不能大于%(max)d")
  52. ]
  53. )
  54. repassword = simple.PasswordField(
  55. label="确认眼神:",
  56. validators=[
  57. validators.EqualTo("password", message="眼神未确认")
  58. ]
  59. )
  60. email = simple.StringField(
  61. label="邮箱",
  62. validators=[
  63. validators.Email(message="邮箱格式不符")
  64. ]
  65. )
  66. gender = core.RadioField(
  67. label="性别:",
  68. choices=[
  69. (1, "女"),
  70. (2, "男")
  71. ],
  72. coerce=int
  73. )
  74. hobby = core.SelectMultipleField(
  75. label="嗜好",
  76. choices=[
  77. (1, "小姐姐"),
  78. (2, "小萝莉"),
  79. (3, "小正太"),
  80. (4, "小哥哥")
  81. ],
  82. coerce=int
  83. )
  84. sub = simple.SubmitField(
  85. label="登陆",
  86. render_kw={"class": "bs"}
  87. )
  88. @app.route("/reg", methods=["GET", "POST"])
  89. def reg():
  90. if request.method == "GET":
  91. regf = RegForm()
  92. return render_template("reg.html", regf=regf)
  93. else:
  94. new_regf = RegForm(formdata=request.form)
  95. if new_regf.validate():
  96. print(new_regf.data.get("gender"))
  97. print(new_regf.data.get("hobby"))
  98. return new_regf.data.get("username")
  99. else:
  100. return render_template("reg.html", regf=new_regf)
  101. if __name__ == '__main__':
  102. app.run()

参考链接:

1.https://wtforms.readthedocs.io/en/stable/

2.https://flask-wtf.readthedocs.io/en/stable/

Flask - WTF和WTForms创建表单的更多相关文章

  1. Flask开发系列之Web表单

    Flask开发系列之Web表单 简单示例 from flask import Flask, request, render_template app = Flask(__name__) @app.ro ...

  2. flask插件系列之Flask-WTF表单

    flask_wtf是flask框架的表单验证模块,可以很方便生成表单,也可以当做json数据交互的验证工具,支持热插拔. 安装 pip install Flask-WTF Flask-WTF其实是对w ...

  3. 使用 WTForms 进行表单验证的例子

    #使用 WTForms 进行表单验证的例子 from wtforms import Form from wtforms import BooleanField from wtforms import ...

  4. flask实战-个人博客-表单

    表单 下面我们来编写所有表单类,personalBlog中主要包含下面这些表单: 登录表单: 文章表单: 评论表单: 博客设置表单: 这里仅介绍登录表单.文章表单.分类表单和评论表单,其他的表单在实现 ...

  5. 在火狐、360等浏览器中,用jquery创建表单并发送的问题

    某些浏览器无法使用js或者jquery直接创建表单并发送,这是由于这些浏览器在提交页面表单时要求页面有完整的标签项即<html><head><title></ ...

  6. SPC2014 :“FOSL”不是替代InfoPath,只是另外一种创建表单的方式

    今天在SPC2014微软宣布他们技术路线图.其实,没有足够证据替代InfoPath,只是另外的一种尝试 - FOSL(对SharePoint列表表单). FOSL使用相同的引擎,用于创建表单的访问服务 ...

  7. activiti自定义流程之整合(二):使用angular js整合ueditor创建表单

    注:整体环境搭建:activiti自定义流程之整合(一):整体环境配置 基础环境搭建完毕,接下来就该正式着手代码编写了,在说代码之前,我觉得有必要先说明一下activit自定义流程的操作. 抛开自定义 ...

  8. activiti自定义流程之自定义表单(二):创建表单

    注:环境配置:activiti自定义流程之自定义表单(一):环境配置 在上一节自定义表单环境搭建好以后,我就正式开始尝试自己创建表单,在后台的处理就比较常规,主要是针对ueditor插件的功能在前端进 ...

  9. 【LABVIEW到C#】2》database的操作(一)之 创建access和创建表单

    namespace添加如下 using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

随机推荐

  1. Ubuntu环境下安装nodejs和npm

    1.安装python-software-properties sudo apt-get install python-software-properties 2.添加ppa curl -sL http ...

  2. bzoj2242 [SDOI2011]计算器——BSGS

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2242 第一次写BSGS,参考了好多好多博客: 然而看到的讲解和模板是一种写法,这道题的网上题 ...

  3. 57.部门职位管理 ExtJs 展示

    1.jobInfo.jsp <%@ page language="java" pageEncoding="UTF-8"%> <script t ...

  4. 4.28 QBXT模拟赛

    NOIP2016提高组模拟赛 ——By wangyurzee7 中文题目名称 迷妹 膜拜 换数游戏 英文题目与子目录名 fans mod game 可执行文件名 fans mod game 输入文件名 ...

  5. P3199 [HNOI2009]最小圈

    传送门 据rqy说有这么一个结论\[ans=\min_{v \in V,F_n(v)\neq \infty} \max_{0 \leq k \leq n - 1} \left[\frac{F_n(v) ...

  6. 关于 node.js 小插曲

    随着web2.0的时代到来,javascript在前端担任了更多的职责,事件也看得到了广泛的应用,node不像rhino那样受java的影响很大,而是将前端浏览器中应用广泛企鹅成熟的事件引入后端,配合 ...

  7. [App Store Connect帮助]一、 App Store Connect 使用入门(1)App Store Connect 工作流程

    您使用 App Store Connect 提交并管理您在 App Store 中销售的 App,使用 TestFlight 分发您 App 的 Beta 版本,接受法律协议,输入您的税务和银行业务信 ...

  8. JavaSE 基础习题整理 - 面向对象篇

    大家好,今天空闲时间整理了一份JavaSE面向对象的常用习题,喜欢的朋友可以关注我.习题来自互联网,不喜勿喷 1.定义长方形类,含: 属性:宽.高(整型): 方法:求周长.面积: 构造方法3个:(1) ...

  9. 324 Wiggle Sort II 摆动排序 II

    给定一个无序的数组nums,将它重新排列成nums[0] < nums[1] > nums[2] < nums[3]...的顺序.例子:(1) 给定nums = [1, 5, 1, ...

  10. Java常用类库(一) : Object 和日期类的简单使用

    顶哥说:Java是世界的,但项目不是! Java有非常多的类库,而我们不会也不用都去学习,毕竟你也仅仅掌握了你手机20%的功能却足够你使用,不是吗? 今天介绍以下类: l  Object l  Dat ...