python-flask-wtforms組件流程源碼
阿新 • • 發佈:2018-01-22
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 corefrom 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組件流程源碼