flask源码系列之-wtforms
一:运行前form内部程序流程
1,开始form
class Loginform(Form): name=simple.StringField( label='用户名', validators=[ validators.DataRequired(message='用户名不能为空'), validators.Length(min=5,max=11,message='长度不能小于%(min)d,不能大于%(max)d') ], widget=widgets.TextInput(), render_kw={'class':'form-control'} )
2,程序开始运行时
form=LoginForm()
这边LoginForm()运行的时候,而loginForm是继承Form,会先执行元类也就是type的__call__方法,然后执行自己的__new__方法,__init__
方法.
3,Form进去,是继承了一个函数
class Form(with_metaclass(FormMeta, BaseForm)): a, 这个函数是用Form继承一个元类FormMeta, def with_metaclass(meta, base=object): return meta("NewBase", (base,), {}) 这个函数就是形成 FormMeta('NewBase',(BaseForm,),{}) ==>NewBase(BaseForm),用一个元类创建一个新类. 并且在这里FormMeta('NewBase',(BaseForm,),{}),也就是调用FormMeta()的__init__方法,如果有__new__的话, 先执行__new__方法. PS:这里formmate相当于type
4, LoginForm()实例化,就会自动执行元类的__call__方法.他的元类是FormMeta.
def __call__(cls, *args, **kwargs): if cls._unbound_fields is None: fields = [] #['name':name_obj] for name in dir(cls): #dir(cls)打印出来里面所有的参数,包括我们穿进去的参数. if not name.startswith('_'): unbound_field = getattr(cls, name) #拿到对象 if hasattr(unbound_field, '_formfield'): fields.append((name, unbound_field)) fields.sort(key=lambda x: (x[1].creation_counter, x[0])) cls._unbound_fields = fields ----------------这里做了两件事 ---找到类的静态字段,也就是我LoginForm下面的name,pwd的字段,循环保存到cls._unbound_fields={name:unbound_field}. ---另外让他们按照进来的顺序排序 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类. cls._wtforms_meta = type('Meta', tuple(bases), {}) #cls._wtforms_meta=所有创建的Meta类 return type.__call__(cls, *args, **kwargs) ---------这里循环该类的所有父类,如果找到Meta类,name就创建Meta
5,执行完元类的__call__方法,现在要执行自己的__new__方法和__init__方法,显然自己没有__new__方法,所有执行__init__方法.
def __init__(self, formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs): meta_obj = self._wtforms_meta() #self._wtforms_meta()是这个Meta类的实例化 #meta可以传进去一个字典{},并当做默认值再html页面显示出来 if meta is not None and isinstance(meta, dict): meta_obj.update_values(meta) super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix) --这里super执行父类的__init__方法,就是BaseForm--- 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) # form.name=form.field self.process(formdata, obj, data=data, **kwargs)
6,执行super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix),
调用父类BaseForm的__init__方法. class BaseForm(object): def __init__(self, fields, prefix='', meta=DefaultMeta()): 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): #这里循环取到(name,unbound_field) options = dict(name=name, prefix=prefix, translations=translations) #并且实例化对象 field = meta.bind_field(self, unbound_field, options) self._fields[name] = field #这里拿到原来字典里的unbound_field替换成Form类的字段String对象. #现在的self._fields={name:string}
7,再回到Form类的__init__里面,执行
for name, field in iteritems(self._fields): setattr(self, name, field) #给name赋值上string属性 self.process(formdata, obj, data=data, **kwargs)
8,执行self.process(formdata, obj, data=data, **kwargs)
def process(self, formdata=None, obj=None, data=None, **kwargs): formdata = self.meta.wrap_formdata(self, formdata) if data is not None: kwargs = dict(data, **kwargs) #kwargs={data:{}}也就是穿进去参数的第二种形式data传参,但是必须是字典形式 for name, field, in iteritems(self._fields): if obj is not None and hasattr(obj, name): #通过obj形式接收参数 field.process(formdata, getattr(obj, name)) elif name in kwargs: field.process(formdata, kwargs[name]) else: field.process(formdata) # 这里主要设置几种值的赋值方法, formdata接收getlist格式的参数 像request.form data:接收字典格式键值对 {name:'12'} obj:接收对象
二:字段继承Field
1,name=simple.StringField()
StringField继承Field
当StringField实例化时,首先执行父类的__new__方法,再执行自己__init__方法. class Field(object): def __new__(cls, *args, **kwargs): if '_form' in kwargs and '_name' in kwargs: return super(Field, cls).__new__(cls) else: return UnboundField(cls, *args, **kwargs)
2,这里执行__new__方法时,数值为空时,执行UnboundField(cls, *args, **kwargs).
class UnboundField(object): _formfield = True creation_counter = 0 def __init__(self, field_class, *args, **kwargs): UnboundField.creation_counter += 1 self.field_class = field_class self.args = args self.kwargs = kwargs self.creation_counter = UnboundField.creation_counter PS:这里开始设置了2个静态字段,creation_counter = 0,在__init__里 UnboundField.creation_counter += 1 所以当实例化一个对象时,则creation_counter+=1.
3,执行__init__方法,因为自己没有,所以用父类的. 初始化数据
def __init__(self, label=None, validators=None, filters=tuple(), description='', id=None, default=None, widget=None, render_kw=None, _form=None, _name=None, _prefix='', _translations=None, _meta=None): if widget is not None: self.widget = widget for v in itertools.chain(self.validators, [self.widget]): flags = getattr(v, 'field_flags', ()) for f in flags: setattr(self.flags, f, True)
三:开始校验
form=Loginform(formdata=request.form)
if form.validate():
return '登录成功'
return render_template('login.html',title='Sign In',form = form)
1,首先还是一样LoginForm()开始进行实例化,然后走里面的代码(略过).
if form.validate() 开始走validate,进行校验. extra = {} #{name:string_obj,pwd:} 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) #这里就是判断是否有钩子函数,并且运行父类validate方法.
2,
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
3,如果if not field.validate(self, extra):就开始运行field.validate,
def validate(self, form, extra_validators=tuple()): self.errors = list(self.process_errors) stop_validation = False try: self.pre_validate(form) except StopValidation as e: if e.args and e.args[0]: self.errors.append(e.args[0]) stop_validation = True except ValueError as e: self.errors.append(e.args[0]) # Run validators if not stop_validation: #如果没有报错则运行这里 chain = itertools.chain(self.validators, extra_validators) #把所有的错误信息合在一起 stop_validation = self._run_validation_chain(form, chain) # Call post_validate try: self.post_validate(form, stop_validation) except ValueError as e: self.errors.append(e.args[0])
4,
stop_validation = self._run_validation_chain(form, chain) for validator in validators: try: validator(form, self) except StopValidation as e: if e.args and e.args[0]: self.errors.append(e.args[0]) return True except ValueError as e: self.errors.append(e.args[0]) return False 把所有的信息的错误信息加到errors里面,然后返回内容 最后if form.validate(): 接收这里的返回信息. 如果是True则运行里面的内容,如果是FALSE,则不运行内容.
四,渲染页面
未做