平面设计网站灵感,seo收费还是免费,做网站游戏网站违法,郑州做企业网站哪家好简介
WTForms是一个支持多个web框架的form组件#xff0c;主要用于对用户请求数据进行验证。 安装#xff1a; pip3 install wtforms
用户登录注册示例
1. 用户登录
当用户登录时候#xff0c;需要对用户提交的用户名和密码进行多种格式校验。如#xff1a;
用户不能为…简介
WTForms是一个支持多个web框架的form组件主要用于对用户请求数据进行验证。 安装 pip3 install wtforms
用户登录注册示例
1. 用户登录
当用户登录时候需要对用户提交的用户名和密码进行多种格式校验。如
用户不能为空用户长度必须大于6密码不能为空密码长度必须大于12密码必须包含 字母、数字、特殊字符等自定义正则
############################## app.py #############################
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core # 字段大部分都在core html5 simple 中
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgetsapp Flask(__name__, template_foldertemplates)
app.debug Trueclass LoginForm(Form):name simple.StringField(label用户名, # 显示名称validators[ # 校验validators.DataRequired(message用户名不能为空.),validators.Length(min6, max18, message用户名长度必须大于%(min)d且小于%(max)d)],widgetwidgets.TextInput(), # 插件render_kw{class: form-control} # 渲染)pwd simple.PasswordField(label密码,validators[validators.DataRequired(message密码不能为空.),validators.Length(min8, message用户名长度必须大于%(min)d),validators.Regexp(regex^(?.*[a-z])(?.*[A-Z])(?.*\d)(?.*[$$!%*?])[A-Za-z\d$$!%*?]{8,},message密码至少8个字符至少1个大写字母1个小写字母1个数字和1个特殊字符)],widgetwidgets.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, formform)else:form LoginForm(formdatarequest.form) # 校验if form.validate():print(用户提交数据通过格式验证提交的值为, form.data)else:print(form.errors)return render_template(login.html, formform)if __name__ __main__:app.run()
############################## login.html #############################
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
h1登录/h1
form methodpost!--input typetext namename--p{{form.name.label}} {{form.name}} {{form.name.errors[0] }}/p!--input typepassword namepwd--p{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}/pinput typesubmit value提交
/form
/body
/html
2. 用户注册
注册页面需要让用户输入用户名、密码、密码重复、性别、爱好等。
############################## app.py #############################
from flask import Flask, render_template, request, redirect
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 widgetsapp Flask(__name__, template_foldertemplates)
app.debug Trueclass RegisterForm(Form):name simple.StringField(label用户名,validators[validators.DataRequired()],widgetwidgets.TextInput(),render_kw{class: form-control},defaultalex)pwd simple.PasswordField(label密码,validators[validators.DataRequired(message密码不能为空.)],widgetwidgets.PasswordInput(),render_kw{class: form-control})pwd_confirm simple.PasswordField(label重复密码,validators[validators.DataRequired(message重复密码不能为空.),validators.EqualTo(pwd, message两次密码输入不一致)],widgetwidgets.PasswordInput(),render_kw{class: form-control})email html5.EmailField(label邮箱,validators[validators.DataRequired(message邮箱不能为空.),validators.Email(message邮箱格式错误)],widgetwidgets.TextInput(input_typeemail),render_kw{class: form-control})gender core.RadioField(label性别,choices((1, 男),(2, 女),),coerceint # 会自动转化为int)city core.SelectField(label城市,choices((bj, 北京),(sh, 上海),))hobby core.SelectMultipleField(label爱好,choices((1, 篮球),(2, 足球),),coerceint)favor core.SelectMultipleField(label喜好,choices((1, 篮球),(2, 足球),),widgetwidgets.ListWidget(prefix_labelFalse),option_widgetwidgets.CheckboxInput(),coerceint,default[1, 2])def __init__(self, *args, **kwargs):super(RegisterForm, self).__init__(*args, **kwargs)self.favor.choices ((1, 篮球), (2, 足球), (3, 羽毛球))def validate_pwd_confirm(self, field): # 钩子函数filed 代表要检验的字段self 代表所有的数据自定义pwd_confirm字段规则例与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}) # data 为form 传值return render_template(register.html, formform)else:form RegisterForm(formdatarequest.form)if form.validate():print(用户提交数据通过格式验证提交的值为, form.data)else:print(form.errors)return render_template(register.html, formform)if __name__ __main__:app.run()
############################## login.html #############################
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
h1用户注册/h1
form methodpost novalidate stylepadding:0 50px{% for item in form %}p{{item.label}}: {{item}} {{item.errors[0] }}/p{% endfor %}input typesubmit value提交
/form
/body
/html
3. meta
使用WTFrom 提供的 csrf_token一般不怎么用
#!/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 md5app Flask(__name__, template_foldertemplates)
app.debug Trueclass MyCSRF(CSRF): # 继承CSRF实现自己的规则Generate a CSRF token based on the users IP. I am probably not verysecure, so dont use me.def setup_form(self, form):self.csrf_context form.meta.csrf_context()self.csrf_secret form.meta.csrf_secretreturn super(MyCSRF, self).setup_form(form)def generate_csrf_token(self, csrf_token):gid self.csrf_secret self.csrf_contexttoken md5(gid.encode(utf-8)).hexdigest()return tokendef 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标签namecsrf_field_name csrf_token# 自动生成标签的值加密用的csrf_secretcsrf_secret xxxxxx# 自动生成标签的值加密用的csrf_contextcsrf_context lambda x: request.url# 生成和比较csrf标签csrf_class MyCSRF# -- i18n# 是否支持本地化# locales Falselocales (zh, en)# 是否对本地化进行缓存cache_translations True# 保存本地化缓存信息的字段translations_cache {}app.route(/index/, methods[GET, POST])
def index():if request.method GET:form TestForm()else:form TestForm(formdatarequest.form)if form.validate():print(form)return render_template(index.html, formform)if __name__ __main__:app.run()
其他
1. metaclass
第一阶段
class MyType(type):def __init__(self, *args, **kwargs):print(MyType创建类,self)super(MyType, self).__init__(*args, **kwargs)def __call__(self, *args, **kwargs):obj super(MyType, self).__call__(*args, **kwargs)print(类创建对象, self, obj)return objclass Foo(object,metaclassMyType):user flepengage 18obj Foo()
第二阶段
class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v dir(cls)obj super(MyType, cls).__call__(*args, **kwargs)return objclass Foo(MyType(MyType, (object,), {})):user wupeiqiage 18obj Foo()
第三阶段
class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v dir(cls)obj super(MyType, cls).__call__(*args, **kwargs)return objdef with_metaclass(arg,base):return MyType(MyType, (base,), {})class Foo(with_metaclass(MyType,object)):user wupeiqiage 18obj Foo()
2. 实例化流程分析
# 源码流程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, datadata, **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, dataunset_value):self.process_errors []if data is unset_value:try:data self.default()except TypeError:data self.defaultself.object_data datatry: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__ 方法返回标签字符串
3. 验证流程分析
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_validatorsNone):self._errors Nonesuccess Truefor 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 Falsereturn successc. 每个字段进行验证时候字段的pre_validate 【预留的扩展】字段的_run_validation_chain对正则和字段的钩子函数进行校验字段的post_validate【预留的扩展】
################################## class FormMeta ###############################
class FormMeta(type):# 创建类时调用的方法def __init__(cls, name, bases, attrs):type.__init__(cls, name, bases, attrs)cls._unbound_fields Nonecls._wtforms_meta None# 实例化类时调用的方法def __call__(cls, *args, **kwargs):if cls._unbound_fields is None:fields []for name in dir(cls):if not name.startswith(_):unbound_field getattr(cls, name)if hasattr(unbound_field, _formfield): # 只要是继承自File_formfield Truefields.append((name, unbound_field)) # 将字段添加至fields fields.sort(keylambda x: (x[1].creation_counter, x[0]))cls._unbound_fields fields # _unbound_fields [字段对应的示例,]if cls._wtforms_meta is None:bases []for mro_class in cls.__mro__:if Meta in mro_class.__dict__:bases.append(mro_class.Meta) # 将所有的Meta添加至bases中cls._wtforms_meta type(Meta, tuple(bases), {}) # 创建一个新的Meta并继承自找到的Meta列表return type.__call__(cls, *args, **kwargs) # 执行type的call方法前面的都是派生的
################################## class Form ###############################
# class Form(BaseForm , classmateFormMeta)
class Form(with_metaclass(FormMeta, BaseForm)):Meta DefaultMetadef __init__(self, formdataNone, objNone, prefix, dataNone, metaNone, **kwargs):meta_obj self._wtforms_meta()if meta is not None and isinstance(meta, dict):meta_obj.update_values(meta)super(Form, self).__init__(self._unbound_fields, metameta_obj, prefixprefix)for name, field in iteritems(self._fields):setattr(self, name, field)self.process(formdata, obj, datadata, **kwargs)def __setitem__(self, name, value):raise TypeError(Fields may not be added to Form instances, only classes.)def __delitem__(self, name):del self._fields[name]setattr(self, name, None)def __delattr__(self, name):if name in self._fields:self.__delitem__(name)else:unbound_field getattr(self.__class__, name, None)if unbound_field is not None and hasattr(unbound_field, _formfield):setattr(self, name, None)else:super(Form, self).__delattr__(name)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)
################################## class BaseForm ###############################
class BaseForm(object):def __init__(self, fields, prefix, metaDefaultMeta()):if prefix and prefix[-1] not in -_;:/.:prefix -self.meta metaself._prefix prefixself._errors Noneself._fields OrderedDict()if hasattr(fields, items):fields fields.items()translations self._get_translations()extra_fields []if meta.csrf:self._csrf meta.build_csrf(self)extra_fields.extend(self._csrf.setup_form(self))for name, unbound_field in itertools.chain(fields, extra_fields):options dict(namename, prefixprefix, translationstranslations)field meta.bind_field(self, unbound_field, options)self._fields[name] field