码迷,mamicode.com
首页 > 编程语言 > 详细

python-flask-wtforms组件流程源码

时间:2018-01-22 21:21:03      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:redirect   request   tac   ict   forms   大于   [1]   creation   label   

  在最开始要弄明白一点,类都是由元类创建的。在定义类 class Foo:pass的时候(类也是对象),就会执行type类或者type派生类的__init__方法,当Foo()时:执行type类或者type派生类的__call__方法,在__call__方法中调用了Foo类的__new__方法创建了一个对象,接着执行__init__方法为这个创建的对象进行赋值属性。

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 widgets
from wtforms import validators

app = Flask(__name__, template_folder=templates)
app.debug = True

#0 定义LogonForm类
class LoginForm(Form):
   #1 StringField类的实例化 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-z\d$@$!%*?&]{8,}", message=密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符) ], widget=widgets.PasswordInput(), render_kw={class: form-control} ) class Meta: csrf = False def validate_pwd(self,*args,**kwargs): pass @app.route(/login, methods=[GET, POST]) def login(): if request.method == GET:
     #2.实例化一个LoginForm对象 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) def test(): form = LoginForm() if __name__ == __main__: app.run()

第0步:

在定义LoginForm类的时候我们看看发生了什么

首先我们要知道metaclass的另外一种方式:with_metaclass

metaclass的另外一种方式:
    class MyType(type):
        def __init__(self,*args,**kwargs):
            print(xxxx)
            super(MyType,self).__init__(*args,**kwargs)

        def __call__(cls, *args, **kwargs):
            obj = cls.__new__(cls,*args, **kwargs)
            cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
            return obj

    def with_metaclass(base):
        return MyType("MyType",(base,),{})

    class Foo(with_metaclass(object)):
        def __init__(self,name):
            self.name = name

    #打印结果:  xxxx    xxxx

所以我们去Form中找找,发现了metaclass的另外一种方式

class Form(with_metaclass(FormMeta, BaseForm)):
    pass

我们再去with_metaclass看看

def with_metaclass(meta, base=object):
    return meta("NewBase", (base,), {})
   # FormMeta("NewBase", (BaseForm,), {}) # 通过FormMeta创建了一个NewBase类,NewBase类继承了BaseForm类
   # 那你有没有疑问,为什么 FormMeta类可以创建类呢? 我们去FormMeta类看看
class FormMeta(type):
  pass
#发现FormMeta继承了type类,所以刚才我们的疑问迎刃而解。

那就是说当LoginForm定义的时候执行了FormMeta类的__init__方法

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

这步完成后 LoginForm类有两个属性:cls._unbound_fields = None和  cls._wtforms_meta = None

第1步:实例化StringField类的对象,首先应该去StringField中找__new__方法

 

class StringField(Field):
    pass
#发现StringField类中没有,那我们就去基类中

 

class Field(object):
        def __new__(cls, *args, **kwargs):
       #判断不成立,走else   
if _form in kwargs and _name in kwargs:   return super(Field, cls).__new__(cls)   else:
         #返回一个UnboundField对象   
return 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    #这个数字,在后面会根据这个进行排序

这步完成后,我们知道 LoginForm的 name和pwd字段都等于UnboundField 的对象

第2步:实例化LoginForm的对象会执行FormMeta的__call__方法

class FormMeta(type):
    def __call__(cls, *args, **kwargs):
        if cls._unbound_fields is None:
            fields = []
            #获取LoginForm类中的所有字段
            for name in dir(cls):
                if not name.startswith(_):
                    #获取该字段的值
                    unbound_field = getattr(cls, name)  #unbound_field 是一个UnboundField对象
                    if hasattr(unbound_field, _formfield):         #    _formfield = True
                        fields.append((name, unbound_field))         # [("name",UnboundField对象),("pwd",UnboundField对象)]
            fields.sort(key=lambda x: (x[1].creation_counter, x[0]))  #根据UnboundField对象的creation_counter属性对fields列表进行排序
            cls._unbound_fields = fields                             # LoginForm._unbound_fields = [("name",UnboundField对象),("pwd",UnboundField对象)]

        if cls._wtforms_meta is None:
            bases = []
            for mro_class in cls.__mro__:   #循环当前类和基类组成的元组
                if Meta in mro_class.__dict__:   #如果类中有Meta类,就把Meta类添加到 bases列表中
                    bases.append(mro_class.Meta)
            cls._wtforms_meta = type(Meta, tuple(bases), {})    #LoginForm._wtforms_meta = 一个新的Meta类,它继承了所有的Meta类,这样做好处在于:通过新Meta类可以取到无论是LoginForm或者LoginForm基类中的任何Meta类
        return type.__call__(cls, *args, **kwargs)

接着到LoginForm或基类中找__new__方法,发现都没有,那就继续找LoginForm或基类中的__intit__方法

 

python-flask-wtforms组件流程源码

标签:redirect   request   tac   ict   forms   大于   [1]   creation   label   

原文地址:https://www.cnblogs.com/liuwei0824/p/8330985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!