zoukankan      html  css  js  c++  java
  • WTForms

      WTForms基础操作,可见骚师博客

      WTForms主要是两个功能:1.生成HTML标签  2.对数据格式进行验证  

      这里主要带大家去看下WTForms源码,是怎么个实现流程?

      首先看到下面的示例代码,捋顺一下类之间的关系

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    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 widgets
    
    app = Flask(__name__, template_folder='templates')
    app.debug = True
    
    
    class LoginForm(Form):
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired(message='用户名不能为空.'),
                validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
            ],
            widget=widgets.TextInput(),
            render_kw={'class': 'form-control'}
    
        )
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.'),
                validators.Length(min=8, message='用户名长度必须大于%(min)d'),
                validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[$@$!%*?&])[A-Za-zd$@$!%*?&]{8,}",
                                  message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
    
            ],
            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('用户提交数据通过格式验证,提交的值为:', form.data)
            else:
                print(form.errors)
            return render_template('login.html', form=form)
    
    if __name__ == '__main__':
        app.run()
    

       form类下,封装了两个field对象,分别为name,pwd,每个field对象下面又给widget封装 了input对象

      第一:生成 HTML标签

      在前端执行{{form.name}}和后端print(form.name)的效果是一样的,所以它会执行对象里的__str__方法,form.name是field对象,也就是执行field对象下的__str__方法,比如StringField,它下面是没有这方法的,但是父类中Field是有的

        def __str__(self):
            return self()
    

       代码执行了return self(),也就会执行field类中的__call__方法

        def __call__(self, **kwargs):
            return self.meta.render_field(self, kwargs)
    

       而在render_field方法中最后又执行了field.widget(field, **render_kw),field.widget是StringField下面封装的widgets.TextInput对象,所以它又会去调用TextInput类下的__call__方法

      在父类input类下,找到了生成html标签的代码

        def __call__(self, field, **kwargs):
            kwargs.setdefault('id', field.id)
            kwargs.setdefault('type', self.input_type)
            if 'value' not in kwargs:
                kwargs['value'] = field._value()
            if 'required' not in kwargs and 'required' in getattr(field, 'flags', []):
                kwargs['required'] = True
            return HTMLString('<input %s>' % self.html_params(name=field.name, **kwargs))
    

      第二:对数据进行验证

    1.  获取前端请求字段数据
    2. 循环每个字段进行正则匹配进行验证
    class InputText(object):
    
        def __str__(self):
            return '<input type="text" />'
    
    class InputEmail(object):
    
        def __str__(self):
            return '<input type="mail" />'
    
    
    class StringField(object):
        def __init__(self,wg,reg):
            self.wg = wg
            self.reg = reg
    
        def __str__(self):
            return str(self.wg)
    
        def valid(self,val):
            import re
            return re.match(self.reg,val)
    
    class LoginForm(object):
        xyy = StringField(wg=InputText(),reg='d+')
        lw = StringField(wg=InputEmail(),reg='w+')
    
        def __str__(self,form):
            self.form = "用户发来的所有数据{xyy:'df',lw:'sdf'}"
    
        def validate(self):
            fields = {'xyy':self.xyy,'lw':self.lw}
            for name,field in fields.items():
                # name是 xyy、。lw
                # field:  StringField(wg=InputText(),reg='d+') / StringField(wg=InputEmail(),reg='w+')
                 # 'df'
                field.valid(self.form[name])
    
    
    #
    # wp = LoginForm()
    # print(wp.xyy)
    # print(wp.lw)
    
    wp = LoginForm(formdata=request.form)
    wp.validate()
    

       从上面我们抽离出来的简单模型,看得出:各个类,分工还是很明确的,input类负责生成标签,而field类负责自己字段数据验证,而form主要统一验证,返回结果

      上面过程只是简单分析,详细分析,请收看下一集

      开始分析前,我们需要了解几个知识点

    • __new__ 用于生成对象
    class Foo(object):
    
        def __init__(self):
            pass
    
    
        def __new__(cls, *args, **kwargs):
            """
            用于生成对象
            :param args:
            :param kwargs:
            :return:
            """
    
            return super(Foo,cls).__new__(cls, *args, **kwargs)
            # return "666"
    
    
    obj = Foo()
    print(obj)
    
    •  __dict__获取所有成员
    class Foo(object):
        AGE = 123
        def __init__(self, na):
            self.name = na
    
    #获取所有成员键值对
    print(Foo.__dict__)
    #获取所有成员的键
    print(dir(Foo))
    
    obj = Foo('laoliu')
    print(obj.__dict__)
    
    •  列表排序
    v = [11,22,334,4,2]
    v.sort()
    print(v)
    
    
    v1 = [
        (11,'alex1'),
        (2,'alex2'),
        (2,'alex3'),
        (7,'alex4'),
    ]
    
    #以元组的第一个元素排序
    v1.sort(key=lambda x:x[0])
    print(v1)
    
    #以元组的第一个元素排序,如果相同,则以第二个元素排序
    v1.sort(key=lambda x:(x[0],x[1]))
    print(v1)
    
    •  __mro__ 按深度优先的关系,找到所有的父类
    class F4(object):
        pass
    
    class F3(F4):
        pass
    
    class F2_5(object):
        pass
    
    class F2(F2_5):
        pass
    
    class F1(F2,F3):
        pass
    
    print(F1.__mro__)
    

       接下来就开始我们快乐的源码分析之旅吧,let's go

      还是看到我们的示例代码中,代码从上往下解释class LoginForm(Form),会去执行创建LoginForm类里的__init__方法,那么创建LoginForm的类是哪个呢,你从父类中看到这句Form(with_metaclass(FormMeta, BaseForm)),就应该很快就能确定是FormMeta,而且FormMeta确实继承type类,所以创建LoginForm类时会去执行FormMeta里的__init__方法(如果这里还不懂,可以去看我的另一篇博客)

        def __init__(cls, name, bases, attrs):
            type.__init__(cls, name, bases, attrs)
            cls._unbound_fields = None
            cls._wtforms_meta = None
    

       在__init__方法里,给LoginForm类封装了两个字段_unbound_fields,_wtforms_meta,都为None

      代码继续往下解释,遇到LoginForm定义两个静态字段name,pwd,进行simple.StringField实例化操作,所以会去执行StringField的__init__方法,执行__init__方法前,它先执行__new__方法,StringField中没有,父类Field中有

        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)
    

       kwargs是 我们传入的参数,我们并没有传入了_form和_name参数,所以它会走else分支,最终name,pwd被赋值UnboundField对象,在这个对象中,封装了StringField类和我们实例的参数,所以创建LoginForm类,会是这个样子

    print(LoginForm.__dict__)
    LoginForm ={
    	'__module__': '__main__', 
    	'name': <1 UnboundField(StringField, (), {'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'}})>, 
    	'pwd': <2 UnboundField(PasswordField, (), {'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>, 
    	'__doc__': None, 
    	'_unbound_fields': None, 
    	'_wtforms_meta': None
    }
    

       你可能会想:怎么不直接实例StringField,而是实例一个UnboundField对象呢?UnboundField能够帮助我们排序,它里面维护了一个计数器,你可能又想了 干嘛要排序?你在前端渲染时,循环form时需要一直保持一个规定顺序,而在后端,我们在定义代码,是从上往下定义字段的,而获取时,使用字典方式获取的,字典是无序的,为了还保持我们定义的顺序,就用上面对象来做到这点

      到视图函数中,实例LoginForm(),会执行下面几个步骤

    1. 执行FormMeta的__call__方法
    2. 执行LoginForm的__new__方法
    3. 执行LoginForm的__init__方法

      首先看到__call__方法中的这段

            if cls._unbound_fields is None:  #此时还为None,会走这个分支
                fields = []
                for name in dir(cls):  #循环 类的成员所有键
                    if not name.startswith('_'):  #排除带_成员,只剩name,pwd
                        unbound_field = getattr(cls, name)  #获取name和pwd对应的UnboundField对象
                        if hasattr(unbound_field, '_formfield'):  #UnboundField类中_formfield默认为True
                            fields.append((name, unbound_field))
                 #进行计算器排序
                fields.sort(key=lambda x: (x[1].creation_counter, x[0]))
                cls._unbound_fields = fields  #最终赋给LoginForm的_unbound_fields 字段
    

       所以,此时_unbound_fields的存储结构为:

    [
        (name, UnboundField对象(计算器,StringField类,参数)),
        (pwd, UnboundField对象(计算器,PasswordField类,参数))    
    ]
    

      我们在看到__call__方法里的这段代码

            if cls._wtforms_meta is None: #此时也是为None
                bases = []
                for mro_class in cls.__mro__:  #获取当前类的所有继承类
    #我们写类里是没有Meta这个字段的,但是继承类Form中Meta = DefaultMeta if 'Meta' in mro_class.__dict__: bases.append(mro_class.Meta) #bases = [DefaultMeta]
           #实例Meta类,继承DefaultMeta,并赋给LoginForm的_wtforms_meta cls._wtforms_meta = type('Meta', tuple(bases), {})

       执行完__call__方法后,此时LoginForm长这样

            class Meta(DefaultMeta,):
                pass
    
            LoginForm ={
                '__module__': '__main__',
                'name': <2 UnboundField(StringField, (), {'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'}})>,
                'pwd': <1 UnboundField(PasswordField, (), {'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>,
                '__doc__': None,
                '_unbound_fields': [
                    (name, UnboundField对象(1,simple.StringField,参数)),
                    (pwd, UnboundField对象(2,simple.PasswordField,参数)),
                ],
                '_wtforms_meta': Meta
    
        }
    

      由于LoginForm和父类中没有__new__方法,没有就不执行

       

      LoginForm中没有定义__init__方法,找到父类中Form的__init__方法执行

       看到这段代码,最后执行了又执行了父类BaseForm的__init__方法,并把_unbound_fields和meta_obj传了进入

            #实例Meta对象(主要用于生成csrf隐藏标签)
            meta_obj = self._wtforms_meta()
            if meta is not None and isinstance(meta, dict):
                meta_obj.update_values(meta)  #如果form里有设置meta,更新到meta_obj
            #执行父类中的__init__方法
            #_unbound_fields =  [
            #        (name, UnboundField对象(1,simple.StringField,参数)),
            #        (pwd, UnboundField对象(2,simple.PasswordField,参数)),
            #    ],
            super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
    

       BaseForm的__init__方法这段代码,真正实例StringField对象和PasswordField是在这下面干的

            if meta.csrf:  #如果有设置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  -->  name,pwd
                #unbound_field --> UnboundField对象(1,simple.StringField,参数)
                #               UnboundField对象(2,simple.PasswordField,参数)
                options = dict(name=name, prefix=prefix, translations=translations)
                field = meta.bind_field(self, unbound_field, options)
                #实例化Field对象后,把LoginForm对象中_fields下每个字段的UnboundField对象替换成Field对象
                self._fields[name] = field
    

       看到meta.bind_field,最终调用 了unbound_field.bind方法

        def bind(self, form, name, prefix='', translations=None, **kwargs):
            kw = dict(
                self.kwargs,
                _form=form,
                _prefix=prefix,
                _name=name,
                _translations=translations,
                **kwargs
            )
            #实例化Field对象,此时参数携带_form和_name,在__new__方法中直接实例Field对象,不再是UnboundField对象
            return self.field_class(*self.args, **kw) 
    

       执行BaseForm的__init__方法后,此时LoginForm对象的存储内容长这样

        form = {
            _fields: {
                    name: StringField对象(),
                    pwd: PasswordField对象(),
                }
        
            }
        
    

       再看到Form.__init__下的另外一段代码

            for name, field in iteritems(self._fields):
                setattr(self, name, field)  #把每个字段设置到对象中,方便支持obj.name,obj.pwd访问
            #为每个字段标签设置默认值和验证的值
            self.process(formdata, obj, data=data, **kwargs)
    

       所以此时的数据结构为

        form = {
            _fields: {
                    name: StringField对象(),
                    pwd: PasswordField对象(),
                }
            name:  StringField对象(widget=widgets.TextInput()),
            pwd:  PasswordField对象(widget=widgets.PasswordInput())
        
            }
        
    

       上面源码分析也只在get请求下,LoginForm不传值

      那如果走post,也是LoginForm传值,它又会怎么走呢?

      请求来的时候,它还是要先走实例LoginForm类的流程,这和get请求里的过程是一样的,唯一不同的,在执行LoginForm父类__init__方法时,self.process(formdata, obj, data=data, **kwargs)这里的formdata是有值的,然后看到process方法里的这段代码

            #循环所有的字段
            '''
                    _fields: {
                    name: StringField对象(),
                    pwd: PasswordField对象(),
                }
            '''
            #formdata 前端传来的值  类似于{'name':alex,'pwd':123}
            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:  #kwargs 和 obj此时都没值,所以会走这个分支
                    #field=StringField...
                    #把前端的值 封装在StringField对象里,此时对象里有 要验证的值 和 正则
                    field.process(formdata)
    

       大概都能猜到field.process(formdata)干了一件什么事,就把前端的值对应字段对象进行封装

            try:
                self.process_data(data)  #进行字段赋值操作
            except ValueError as e:
                self.process_errors.append(e.args[0])
    
            if formdata is not None:
                if self.name in formdata:
                    self.raw_data = formdata.getlist(self.name)
                else:
                    self.raw_data = []
    
                try:
                    self.process_formdata(self.raw_data)  #也是进行字段赋值操作
                except ValueError as e:
                    self.process_errors.append(e.args[0])
    

       

      传值form后,接下来的就是验证了,猜它都会循环每个字段,调用每个字段的验证方法

      接下来就看到LoginForm的验证方法

        def validate(self):
            extra = {}
            for name in self._fields:
                #获取每个字段的钩子函数 validate_name validate_pwd
                inline = getattr(self.__class__, 'validate_%s' % name, None)
                if inline is not None:
                    extra[name] = [inline]
            '''
            前提是你有定义这么一个函数
            添加完后extra = {
                name : [validate_name],
                pwd : [validate_pwd]
            }
            '''
            return super(Form, self).validate(extra)
    

       而在执行父类里的验证方法里,就负责调用了每个字段里的验证方法

        def validate(self, extra_validators=None):
            self._errors = None
            success = True
            '''
            extra_validators = {
                name : [validate_name],
                pwd : [validate_pwd]
            }
            '''
            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()
                #调用字段的验证方法,并传入钩子函数,self为form对象,到时候用它里面的正则和要验证的值
                if not field.validate(self, extra):
                    success = False
            return success
    

       在字段的验证方法中,有这么一段,调用了_run_validation_chain方法

            if not stop_validation:
                '''
                validators=[
                    validators.DataRequired(message='用户名不能为空.'),
                    validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
                ]
                extra_validators=[钩子函数]
                '''
                chain = itertools.chain(self.validators, extra_validators)
                stop_validation = self._run_validation_chain(form, chain)
    

       执行_run_validation_chain

            #循环每条验证规则进行验证
            for validator in validators:
                try:
                    #validator要么是钩子函数 要么是对象,对象则又去执行__call__方法
                    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
    

     分析实例代码

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask, render_template, request, redirect
    from wtforms import Form
    from wtforms.fields import simple
    from wtforms import validators
    from wtforms import widgets
    
    app = Flask(__name__, template_folder='templates')
    
    app.debug = True
    
    
    # 1.由于 metaclass=FormMeta,所以LoginForm是由FormMeta创建
    # 2. 执行 FormMeta.__init__
    #       LoginForm._unbound_fields = None
    #       LoginForm._wtforms_meta = None
    # 3. 解释字段:
    #       name = simple.StringField(...)
    #       pwd = simple.PasswordField(...)
    #    结果:
    #       LoginForm.name = UnboundField(simple.StringField,StringField的所有参数)
    #       LoginForm.pwd = UnboundField(simple.PasswordField,PasswordField的所有参数)
    
    class LoginForm(Form):
        # 字段(内部包含正则表达式)
        name = simple.StringField(
            label='用户名',
            validators=[
                validators.DataRequired(message='用户名不能为空.'),
                validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
            ],
            widget=widgets.TextInput(), # 页面上显示的插件
            render_kw={'class': 'form-control'}
        )
        # 字段(内部包含正则表达式)
        pwd = simple.PasswordField(
            label='密码',
            validators=[
                validators.DataRequired(message='密码不能为空.'),
                validators.Length(min=8, message='用户名长度必须大于%(min)d'),
                validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[$@$!%*?&])[A-Za-zd$@$!%*?&]{8,}",
                                  message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')
    
            ],
            widget=widgets.PasswordInput(),
            render_kw={'class': 'form-control'}
        )
        def validate_name(self,form):
            pass
    
    """
    print(LoginForm.__dict__)
    LoginForm ={
    	'__module__': '__main__', 
    	'name': <1 UnboundField(StringField, (), {'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'}})>, 
    	'pwd': <2 UnboundField(PasswordField, (), {'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>, 
    	'__doc__': None, 
    	'_unbound_fields': None, 
    	'_wtforms_meta': None
    }
    """
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        # 实例LoginForm
        # 1. 执行FormMeta的__call__方法
        """
            class Meta(DefaultMeta,):
                pass
    
            LoginForm ={
                '__module__': '__main__',
                'name': <2 UnboundField(StringField, (), {'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'}})>,
                'pwd': <1 UnboundField(PasswordField, (), {'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>,
                '__doc__': None,
                '_unbound_fields': [
                    (name, UnboundField对象(1,simple.StringField,参数)),
                    (pwd, UnboundField对象(2,simple.PasswordField,参数)),
                ],
                '_wtforms_meta': Meta
    
        }
        """
        # 2. 执行LoginForm的__new__方法
        #    pass
        # 3. 执行LoginForm的__init__方法
        """
         LoginForm ={
                '__module__': '__main__',
                'name': <2 UnboundField(StringField, (), {'label': '用户名', 'validators': [<wtforms.validators.DataRequired object at 0x00000000037DAEB8>, <wtforms.validators.Length object at 0x000000000382B048>], 'widget': <wtforms.widgets.core.TextInput object at 0x000000000382B080>, 'render_kw': {'class': 'form-control'}})>,
                'pwd': <1 UnboundField(PasswordField, (), {'label': '密码', 'validators': [<wtforms.validators.DataRequired object at 0x000000000382B0F0>, <wtforms.validators.Length object at 0x000000000382B128>, <wtforms.validators.Regexp object at 0x000000000382B160>], 'widget': <wtforms.widgets.core.PasswordInput object at 0x000000000382B208>, 'render_kw': {'class': 'form-control'}})>,
                '__doc__': None,
                '_unbound_fields': [
                    (name, UnboundField对象(1,simple.StringField,参数)),
                    (pwd, UnboundField对象(2,simple.PasswordField,参数)),
                ],
                '_wtforms_meta': Meta
    
            }
        form = {
            _fields: {
                    name: StringField对象(),
                    pwd: PasswordField对象(),
                }
            name:  StringField对象(widget=widgets.TextInput()),
            pwd:  PasswordField对象(widget=widgets.PasswordInput())
        
            }
        
        """
        if request.method == 'GET':
    
            form = LoginForm()
            # form._fields['name']
            # form.name = StringField对象()
            """
            1. StringField对象.__str__
            2. StringField对象.__call__
            3. meta.render_field(StringField对象,)
            4. StringField对象.widget(field, **render_kw)
            5. 插件.__call__()
            """
            print(form.name) #
            """
            0. Form.__iter__: 返回所有字段对象
                1. StringField对象.__str__
                2. StringField对象.__call__
                3. meta.render_field(StringField对象,)
                4. StringField对象.widget(field, **render_kw)
                5. 插件.__call__()
            """
            for item in form:
                # item是fields中的每一个字段
                print(item)
    
            return render_template('login.html',form=form)
        else:
            # 上述流程+
            # 从请求中获取每个值,再复制到到每个字段对象中
            """
             form = {
                _fields: {
                        name: StringField对象(data=你输入的用户名),
                        pwd: PasswordField对象(pwd=你输入的密码),
                    }
                name:  StringField对象(widget=widgets.TextInput(data=你输入的用户名)),
                pwd:  PasswordField对象(widget=widgets.PasswordInput(pwd=你输入的密码))
            
                }
            """
            # 请求发过来的值
            form = LoginForm(formdata=request.form) # 值.getlist('name')
    
            # 实例:编辑
            # # 从数据库对象
            # form = LoginForm(obj='值') # 值.name/值.pwd
            #
            # # 字典 {}
            # form = LoginForm(data=request.form) # 值['name']
    
            # 1. 循环所有的字段
            # 2. 获取每个字段的钩子函数
            # 3. 为每个字段执行他的验证流程 字段.validate(钩子函数+内置验证规则)
            if form.validate():
                print(form.data)
            else:
                print(form.errors)
    
    
    if __name__ == '__main__':
        app.run()
    
  • 相关阅读:
    Lambda表达式、依赖倒置
    ASP.NET vNext 概述
    Uname
    RHEL4 i386下安装rdesktop【原创】
    Taxonomy of class loader problems encountered when using Jakarta Commons Logging(转)
    How to decompile class file in Java and Eclipse
    先有的资源,能看的速度看,不能看的,抽时间看。说不定那天就真的打不开了(转)
    Google App Engine 学习和实践
    【VBA研究】VBA通过HTTP协议实现邮件轨迹跟踪查询
    js正則表達式语法
  • 原文地址:https://www.cnblogs.com/xinsiwei18/p/9609764.html
Copyright © 2011-2022 走看看