在最开始要弄明白一点,类都是由元类创建的。在定义类 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)(?=.*[[email protected]$!%*?&])[A-Za-z\[email protected]$!%*?&]{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__方法