1. 程式人生 > >python-flask-wtforms組件流程源碼

python-flask-wtforms組件流程源碼

tor 們的 method xxx 大寫 源碼 屬性 一點 繼承

  在最開始要弄明白一點,類都是由元類創建的。在定義類 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組件流程源碼