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()
    
  • 相关阅读:
    BZOJ.3990.[SDOI2015]排序(DFS)
    BZOJ.1040.[ZJOI2008]骑士(树形DP)
    BZOJ.2246.[SDOI2011]迷宫探险(DP 记忆化搜索 概率)
    BZOJ.3209.花神的数论题(数位DP)
    UVA.1640.The Counting Problem / BZOJ.1833.[ZJOI2010]数字计数(数位DP)
    HDU.3652.B-number(数位DP)
    BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)
    BZOJ.4832.[Lydsy1704月赛]抵制克苏恩(期望DP)
    BZOJ.1025.[SCOI2009]游戏(背包DP)
    BZOJ.3257.树的难题(树形DP)
  • 原文地址:https://www.cnblogs.com/xinsiwei18/p/9609764.html
Copyright © 2011-2022 走看看