The first thing to figure out is that the class is created by the Meta class. When the class class Foo:pass is defined (the class is also an object), the __init__ method of the type class or type derived class is executed, when Foo (): Executes the __call__ method of the Type class or type-derived class, in __call__ Method calls the __new__ method of the Foo class to create an object, and then executes the __init__ method to assign a property to the created object.
fromFlaskImportFlask, render_template, request, redirect fromWtformsImportForm fromWtforms.fieldsImportCore fromWtforms.fieldsImportHTML5 fromWtforms.fieldsImport Simple fromWtformsImportWidgets fromWtformsImportValidatorsapp= Flask (__name__, template_folder='Templates') App.debug=True#0 define the LogonForm class classLoginForm (Form):
#1 instantiation of the Stringfield class name=Simple . Stringfield (Label='User name', validators=[validators. datarequired (Message='the user name cannot be empty.'), validators. Length (min=6, Max=18, message='user name must be longer than% (min) d and less than% (max) d')], widget=widgets. TextInput (), render_kw={'class':'Form-control'}) PWD=Simple . Passwordfield (Label='Password', validators=[validators. datarequired (Message='The password cannot be empty.'), validators. Length (min=8, message='user name must be longer than% (min) d'), validators. Regexp (Regex="^ (? =.*[a-z]) (? =.*[a-z]) (? =.*\d) (? =.*[[email Protected]$!%*?&]) [A-za-z\[email protected]$!%*?&]{8,} ", Message='password At least 8 characters, at least 1 uppercase letters, 1 lowercase letters, 1 digits and a special character')], widget=widgets. Passwordinput (), render_kw={'class':'Form-control'} ) classMETA:CSRF=FalsedefValidate_pwd (self,*args,**Kwargs):Pass@app. Route ('/login', methods=['GET','POST'])deflogin ():ifRequest.method = ='GET':
#2. Instantiate a LoginForm object form=LoginForm ()returnRender_template ('login.html', form=form)Else: Form= LoginForm (formdata=Request.Form)ifform.validate ():Print('the user submits the data through the format validation, the submitted value is:', Form.data)Else: Print(form.errors)returnRender_template ('login.html', form=form)defTest (): Form=LoginForm ()if __name__=='__main__': App.run ()
No. 0 Step:
We'll see what happens when we define the LoginForm class.
First we need to know another way of Metaclass:with_metaclass
another way to Metaclass:classMyType (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) returnobjdefWith_metaclass (Base):returnMyType ("MyType", (base,), {})classFoo (With_metaclass (object)):def __init__(self,name): Self.name=name#Print Result: xxxx xxxx
So we went to the form and found another way to find Metaclass.
class Form (With_metaclass (Formmeta, BaseForm)): Pass
Let's go see with_metaclass again.
def with_metaclass (meta, base=object): return Meta ("newbase" , (base,), {})
Formmeta ("newbase", (baseform,), {}) # created a newbase class through Formmeta, Newbase class inherits the BaseForm class
# so you have no doubt why the Formmeta class can create classes? let's go to Formmeta class and see
class Formmeta (type):
Pass
#发现FormMeta继承了type类, so we solved the problem just now.
That means that the __init__ method of the Formmeta class was executed when the loginform was defined.
class Formmeta (type): def __init__ (CLS, name, bases, attrs): type. __init__ (CLS, name, bases, attrs) = none = None
After this step is complete, the LoginForm class has two properties:Cls._unbound_fields = None and Cls._wtforms_meta = none
1th Step: Instantiate the object of Stringfield class, first should go to Stringfield to find __new__ method
class Stringfield (Field): Pass
# found No in the Stringfield class, then we go to the base class
classField (object):def __new__(CLS, *args, * *Kwargs):
#判断不成立, go else.if '_form' inchKwargs and '_name' inchKwargs:returnSuper (Field, CLS).__new__(CLS)Else:
#返回一个UnboundField对象returnUnboundfield (CLS, *args, **kwargs)
class Unboundfield (object): = True = 0 def__init__(self, field_class, *args, * *Kwargs): + = 1 = Field_class= args = Kwargs = Unboundfield.creation_counter #这个数字, which will be sorted by this later.
When this is done, we know that LoginForm's name and PWD fields are equal to Unboundfield objects
2nd step: Instantiating an LoginForm object executes the Formmeta __call__ method
classFormmeta (type):def __call__(CLS, *args, * *Kwargs):ifCls._unbound_fields isNone:fields= [] #get all fields in the LoginForm class forNameinchdir (CLS):if notName.startswith ('_'): #gets the value of the fieldUnbound_field = GetAttr (CLS, name)#Unbound_field is a Unboundfield object ifHasattr (Unbound_field,'_formfield'):#_formfield = TrueFields.Append ((name, Unbound_field))#[("Name", Unboundfield object), ("pwd", Unboundfield object)]Fields.sort (key=LambdaX: (X[1].creation_counter, x[0]))#sorts the fields list based on the Creation_counter property of the Unboundfield objectCls._unbound_fields = Fields#loginform._unbound_fields = [("Name", Unboundfield object), ("pwd", Unboundfield object)] ifCls._wtforms_meta isnone:bases= [] forMro_classinchCls.__mro__:#loops The tuple of the current class and base class if 'Meta' inchMro_class.__dict__:#If there is a meta class in the class, add the meta class to the bases listBases.append (Mro_class. Meta) Cls._wtforms_meta= Type ('Meta', tuple (bases), {})#Loginform._wtforms_meta = A new meta class, which inherits all meta classes, has the advantage of being able to fetch any meta class in either LoginForm or LoginForm base class through the new meta class returnType.__call__(CLS, *args, **kwargs)
Then go to the LoginForm or base class to find __new__ method, find none, then continue to find LoginForm or base class __intit__ method
Python-flask-wtforms Component Process Source code