flask之wtforms
本篇导航:
一、wtforms组件的使用
1、flask中的wtforms
WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。
安装:
pip3 install wtforms
2、wtforms组件的使用之登录验证
1)图示

2)manage.py
from flask import Flask,render_template,request,redirect
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import Form
from wtforms import validators
from wtforms import widgets
app = Flask(__name__,template_folder="templates") class Myvalidators(object):
'''自定义验证规则'''
def __init__(self,message):
self.message = message
def __call__(self, form, field):
print(field.data,"用户输入的信息")
if field.data == "haiyan":
return None
raise validators.ValidationError(self.message) class LoginForm(Form):
'''Form'''
name = simple.StringField(
label="用户名",
widget=widgets.TextInput(),
validators=[
Myvalidators(message="用户名必须是haiyan"),#也可以自定义正则
validators.DataRequired(message="用户名不能为空"),
validators.Length(max=8,min=3,message="用户名长度必须大于%(max)d且小于%(min)d")
],
render_kw={"class":"form-control"} #设置属性
) pwd = simple.PasswordField(
label="密码",
validators=[
validators.DataRequired(message="密码不能为空"),
validators.Length(max=8,min=3,message="密码长度必须大于%(max)d且小于%(min)d"),
validators.Regexp(regex="\d+",message="密码必须是数字"),
],
widget=widgets.PasswordInput(),
render_kw={"class":"form-control"}
) @app.route('/login',methods=["GET","POST"])
def login():
if request.method =="GET":
form = LoginForm()
return render_template("login.html",form=form)
else:
form = LoginForm(formdata=request.form)
if form.validate():
print("用户提交的数据用过格式验证,值为:%s"%form.data)
return "登录成功"
else:
print(form.errors,"错误信息")
return render_template("login.html",form=form) if __name__ == '__main__':
# app.__call__()
app.run(debug=True)
3)login.html
<body>
<form action="" method="post" novalidate>
<p>{{ form.name.label }} {{ form.name }} {{ form.name.errors.0 }}</p>
<p>{{ form.pwd.label }} {{ form.pwd }} {{ form.pwd.errors.0 }}</p>
<input type="submit" value="提交">
<!--用户名:<input type="text">-->
<!--密码:<input type="password">-->
<!--<input type="submit" value="提交">-->
</form>
</body>
3、wtforms组件的使用之用户注册
1)图示

2)manage.py
from flask import Flask,render_template,redirect,request
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets app = Flask(__name__,template_folder="templates")
app.debug = True =======================simple===========================
class RegisterForm(Form):
name = simple.StringField(
label="用户名",
validators=[
validators.DataRequired()
],
widget=widgets.TextInput(),
render_kw={"class":"form-control"},
default="haiyan"
)
pwd = simple.PasswordField(
label="密码",
validators=[
validators.DataRequired(message="密码不能为空")
]
)
pwd_confim = simple.PasswordField(
label="重复密码",
validators=[
validators.DataRequired(message='重复密码不能为空.'),
validators.EqualTo('pwd',message="两次密码不一致")
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) ========================html5============================
email = html5.EmailField( #注意这里用的是html5.EmailField
label='邮箱',
validators=[
validators.DataRequired(message='邮箱不能为空.'),
validators.Email(message='邮箱格式错误')
],
widget=widgets.TextInput(input_type='email'),
render_kw={'class': 'form-control'}
) ===================以下是用core来调用的=======================
gender = core.RadioField(
label="性别",
choices=(
(1,"男"),
(1,"女"),
),
coerce=int #限制是int类型的
)
city = core.SelectField(
label="城市",
choices=(
("bj","北京"),
("sh","上海"),
)
)
hobby = core.SelectMultipleField(
label='爱好',
choices=(
(1, '篮球'),
(2, '足球'),
),
coerce=int
)
favor = core.SelectMultipleField(
label="喜好",
choices=(
(1, '篮球'),
(2, '足球'),
),
widget = widgets.ListWidget(prefix_label=False),
option_widget = widgets.CheckboxInput(),
coerce = int,
default = [1, 2]
) def __init__(self,*args,**kwargs): #这里的self是一个RegisterForm对象
'''重写__init__方法'''
super(RegisterForm,self).__init__(*args, **kwargs) #继承父类的init方法
self.favor.choices =((1, '篮球'), (2, '足球'), (3, '羽毛球')) #吧RegisterForm这个类里面的favor重新赋值 def validate_pwd_confim(self,field,):
'''
自定义pwd_config字段规则,例:与pwd字段是否一致
:param field:
:return:
'''
# 最开始初始化时,self.data中已经有所有的值
if field.data != self.data['pwd']:
# raise validators.ValidationError("密码不一致") # 继续后续验证
raise validators.StopValidation("密码不一致") # 不再继续后续验证 @app.route('/register',methods=["GET","POST"])
def register():
if request.method=="GET":
form = RegisterForm(data={'gender': 1}) #默认是1,
return render_template("register.html",form=form)
else:
form = RegisterForm(formdata=request.form)
if form.validate(): #判断是否验证成功
print('用户提交数据通过格式验证,提交的值为:', form.data) #所有的正确信息
else:
print(form.errors) #所有的错误信息
return render_template('register.html', form=form) if __name__ == '__main__':
app.run()
3)register.html
<body>
<h1>用户注册</h1>
<form method="post" novalidate style="padding:0 50px">
{% for item in form %}
<p>{{item.label}}: {{item}} {{item.errors[0] }}</p>
{% endfor %}
<input type="submit" value="提交">
</form>
</body>
4、mate
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect, session
from wtforms import Form
from wtforms.csrf.core import CSRF
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets
from hashlib import md5 app = Flask(__name__, template_folder='templates')
app.debug = True class MyCSRF(CSRF):
"""
Generate a CSRF token based on the user's IP. I am probably not very
secure, so don't use me.
""" def setup_form(self, form):
self.csrf_context = form.meta.csrf_context()
self.csrf_secret = form.meta.csrf_secret
return super(MyCSRF, self).setup_form(form) def generate_csrf_token(self, csrf_token):
gid = self.csrf_secret + self.csrf_context
token = md5(gid.encode('utf-8')).hexdigest()
return token def validate_csrf_token(self, form, field):
print(field.data, field.current_token)
if field.data != field.current_token:
raise ValueError('Invalid CSRF') class TestForm(Form):
name = html5.EmailField(label='用户名')
pwd = simple.StringField(label='密码') class Meta:
# -- CSRF
# 是否自动生成CSRF标签
csrf = True
# 生成CSRF标签name
csrf_field_name = 'csrf_token' # 自动生成标签的值,加密用的csrf_secret
csrf_secret = 'xxxxxx'
# 自动生成标签的值,加密用的csrf_context
csrf_context = lambda x: request.url
# 生成和比较csrf标签
csrf_class = MyCSRF # -- i18n
# 是否支持本地化
# locales = False
locales = ('zh', 'en')
# 是否对本地化进行缓存
cache_translations = True
# 保存本地化缓存信息的字段
translations_cache = {} @app.route('/index/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
form = TestForm()
else:
form = TestForm(formdata=request.form)
if form.validate():
print(form)
return render_template('index.html', form=form) if __name__ == '__main__':
app.run()
二、自定义Form组件
1、wtforms源码流程
1)实例化流程分析
# 源码流程
1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中
2. 执行构造方法 a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。
即:
_fields = {
name: wtforms.fields.core.StringField(),
} PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField() b. 循环_fields,为对象设置属性
for name, field in iteritems(self._fields):
# Set all the fields to attributes so that they obscure the class
# attributes with the same names.
setattr(self, name, field)
c. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs)
优先级:obj,data,formdata; 再循环执行每个字段的process方法,为每个字段设置值:
for name, field, in iteritems(self._fields):
if obj is not None and hasattr(obj, name):
field.process(formdata, getattr(obj, name))
elif name in kwargs:
field.process(formdata, kwargs[name])
else:
field.process(formdata) 执行每个字段的process方法,为字段的data和字段的raw_data赋值
def process(self, formdata, data=unset_value):
self.process_errors = []
if data is unset_value:
try:
data = self.default()
except TypeError:
data = self.default self.object_data = data try:
self.process_data(data)
except ValueError as e:
self.process_errors.append(e.args[0]) if formdata:
try:
if self.name in formdata:
self.raw_data = formdata.getlist(self.name)
else:
self.raw_data = []
self.process_formdata(self.raw_data)
except ValueError as e:
self.process_errors.append(e.args[0]) try:
for filter in self.filters:
self.data = filter(self.data)
except ValueError as e:
self.process_errors.append(e.args[0]) d. 页面上执行print(form.name) 时,打印标签 因为执行了:
字段的 __str__ 方法
字符的 __call__ 方法
self.meta.render_field(self, kwargs)
def render_field(self, field, render_kw):
other_kw = getattr(field, 'render_kw', None)
if other_kw is not None:
render_kw = dict(other_kw, **render_kw)
return field.widget(field, **render_kw)
执行字段的插件对象的 __call__ 方法,返回标签字符串
2)验证流程分析
a. 执行form的validate方法,获取钩子方法
def validate(self):
extra = {}
for name in self._fields:
inline = getattr(self.__class__, 'validate_%s' % name, None)
if inline is not None:
extra[name] = [inline] return super(Form, self).validate(extra)
b. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数)
def validate(self, extra_validators=None):
self._errors = None
success = True
for name, field in iteritems(self._fields):
if extra_validators is not None and name in extra_validators:
extra = extra_validators[name]
else:
extra = tuple()
if not field.validate(self, extra):
success = False
return success
c. 每个字段进行验证时候
字段的pre_validate 【预留的扩展】
字段的_run_validation_chain,对正则和字段的钩子函数进行校验
字段的post_validate【预留的扩展】
2、自定义Form组件
#!usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask,render_template,request,Markup
app = Flask(__name__,template_folder="templates")
app.debug = True
# ==============通过这几个类就可以显示了-==============
#插件
class Widget(object):
pass class InputText(Widget):
def __call__(self, *args, **kwargs): return "<input type='text' name='name'>" class TextArea(Widget):
def __call__(self, *args, **kwargs):
return Markup("<textarea name='email'></textarea>") #Form
class BaseForm(object):
def __init__(self):
#获取当前所有的字段
_fields = {}
for name, field in self.__class__.__dict__.items():
if isinstance(field, Field): # 筛选出字段是name和emailDe
_fields[name] = field
self._fields = _fields
self.data = {}
# print(_fields) # {'name': 111, 'email': 222} def validate(self,request_data):
#先找到所有的字段,在执行每一个字段的validate方法
flag = True
for name, field in self._fields.items():
input_val = request_data.get(name,"") #用户输入的值
result= field.validate(input_val) #每一个字段自己校验
print("???????????",input_val,result)
if not result:
flag = False
else:
self.data[name] = input_val
return flag
#字段
class Field(object):
'''所有类的基类'''
def __str__(self): #python中的静态字段通过类能找到,通过对象也能找到
return Markup(self.widget()) #self就是StringField,self class StringField(Field): #每个字段打印的时候都要去执行__str__,所以选择放在基类里面,自己没有就调用父类的
widget = InputText()
def validate(self,val):
if val:
return True class EmaliField(Field):
widget = TextArea()
reg = ".*@.*" def validate(self,val):
import re
print(re.match(self.reg,val),"************")
if re.match(self.reg,val):
return True # ===============使用===============
class LoginForm(BaseForm):
name = StringField()
email = EmaliField() @app.route('/index', methods=["GET","POST"])
def index():
form = LoginForm()
ret = form.validate(request.form)
print("验证成功",ret)
print("验证成功的值",form.data)
# print(form.name)
# print(form.email)
return render_template("index.html",form=form) if __name__ == '__main__':
app.run()
flask之wtforms的更多相关文章
- Flask插件wtforms、Flask文件上传和Echarts柱状图
一.wtforms 类比Django的Form组件Form组件的主要应用是帮助我们自动生成HTML代码和做一些表单数据的验证 flask的wtforms用法跟Form组件大同小异参考文章:https: ...
- 85、flask之wtforms
本篇导航: wtforms组件的使用 自定义From组件 一.wtforms组件的使用 1.flask中的wtforms WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进 ...
- Flask的WTforms
一.简单介绍 WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 类似于Django中的modelform 安装: pip3 install wtforms 二.简 ...
- Flask之wtforms源码分析
一.wtforms源码流程 1.实例化流程分析 # 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...
- 【Flask】WTForms基本使用
# WTForms笔记:这个库一般有两个作用.第一个就是做表单验证,把用户提交上来的数据进行验证是否合法.第二个就是做模版渲染. ### 做表单验证:1. 自定义一个表单类,继承自wtforms.Fo ...
- 11,flask之--WTForms
WTForms是什么? 相当于django的ModelForm. 在网页中,为了和用户进行信息交互总是不得不出现一些表单.flask设计了WTForm表单库来使flask可以更加简便地管理操作表单数据 ...
- flask flask_session,WTForms
一.Flask_session 本质上,就是是cookie 下的session存储在redis中,方便快速取得session from flask import Flask,session from ...
- flask之wtforms 表单验证(一)
一 安装wtforms pip install wtforms 二 导入相关模块及对象 from wtforms import Form, widgets, validators from wtf ...
- 【Flask】WTForms文件上传下载
# 文件上传笔记:1. 在模版中,form表单中,需要指定`encotype='multipart/form-data'`才能上传文件.2. 在后台如果想要获取上传的文件,那么应该使用`request ...
随机推荐
- SpringBoot入门-2(两种热部署方式)
在编写代码的时候,你会发现我们只是简单把打印信息改变了,就需要重新部署,如果是这样的编码方式,那么我们估计一天下来就真的是打几个Hello World就下班了.那么如何解决热部署的问题呢?那就是spr ...
- Node.js实战项目学习系列(2) 开发环境和调试工具
前言 上一节让我们对Node.js有一个初步的了解,那么现在可以开始正式学习下Node.js的开发了,但是任何一门语言要设计到开发,就必须先学习开发环境以及调试.本文将主要讲解这些内容. 本文涉及到的 ...
- tex中把参考文献标题删除
如果是book类<br>\renewcommand\bibname{}<br> 如果是article类<br>\renewcommand\refname{}
- luogu P5294 [HNOI2019]序列
传送门 这个什么鬼证明直接看uoj的题解吧根本不会证明 首先方案一定是若干段等值的\(B\),然后对于一段,\(B\)的值应该是\(A\)的平均值.这个最优方案是可以线性构造的,也就是维护以区间平均值 ...
- webpack学习笔记——path
__dirname + '/src' path.resolve(__dirname, 'src') path.resolve(__dirname, './src') path.join(__dirna ...
- Codeforces Round #501 (Div. 3) D. Walking Between Houses
题目链接 题意:给你三个数n,k,sn,k,sn,k,s,让你构造一个长度为k的数列,使得相邻两项差值的绝对值之和为sss, ∑i=1n∣a[i]−a[i−1]∣,a[0]=1\sum_{i=1}^n ...
- nginx禁止ip登录,只允许域名访问
公司要求,线上solr.kibana要求只能通过域名进行访问,禁止用ip+端口进行登录访问,那么,下面介绍下我是如何实现的 1.禁止ip,允许域名访问 如下图,默认安装好nginx,不让ip方式访问, ...
- PYthon3:函数实现“自动售卖机”功能
题目: 自动贩卖机: # 只接受1元.5元.10元的纸币或硬币,可以1块,5元,10元.# 饮料只有橙汁.椰汁.矿泉水.早餐奶,售价分别是3.5,4,2,4.5# 写一个函数用来表示贩卖机的功能:用户 ...
- 查不到opencv版本的问题
检查opencv版本:pkg-config --modversion opencv 前两天卸载了opencv3.0,想重装2.4版本.安装是没有问题,但现在查不到opencv版本,程序也编译不通过. ...
- spring事务源码分析结合mybatis源码(一)
最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析 ...