• 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
    View Code

    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)
    View Code

    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}
    View Code

    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:接收对象
    View Code

    二:字段继承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)
    View Code

    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.
    View Code

    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)
    View Code

    三:开始校验

    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])
    View Code

    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,则不运行内容.

    四,渲染页面

    未做

     



  • 相关阅读:
    Codeforces Round #551 (Div. 2) F. Serval and Bonus Problem (DP/FFT)
    Codeforces Round #551 (Div. 2) E. Serval and Snake (交互题)
    BZOJ 5495: [2019省队联测]异或粽子 (trie树)
    洛谷【P2669】NOIP2015普及组 T1金币
    解决Win 10上SSD缓慢问题
    如何保障数据安全
    一个网工的linux学习过程
    JS实现select去除option的使用注意事项
    codevs1506传话(kosaraju算法)
    我的园子
  • 原文地址:https://www.cnblogs.com/52forjie/p/8295153.html
Copyright © 2020-2023  润新知