zoukankan      html  css  js  c++  java
  • 281 Flask学习【第10篇】:自定义Form组件

    自定义Form组件

    一、wtforms源码流程

    1、实例化流程分析

     1 # 源码流程
     2     1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中
     3     2. 执行构造方法
     4         
     5         a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。
     6             即:
     7                 _fields = {
     8                     name: wtforms.fields.core.StringField(),
     9                 }
    10                 
    11             PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField()
    12         
    13         b. 循环_fields,为对象设置属性
    14             for name, field in iteritems(self._fields):
    15                 # Set all the fields to attributes so that they obscure the class
    16                 # attributes with the same names.
    17                 setattr(self, name, field)
    18         c. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs)
    19             优先级:obj,data,formdata;
    20             
    21             再循环执行每个字段的process方法,为每个字段设置值:
    22             for name, field, in iteritems(self._fields):
    23                 if obj is not None and hasattr(obj, name):
    24                     field.process(formdata, getattr(obj, name))
    25                 elif name in kwargs:
    26                     field.process(formdata, kwargs[name])
    27                 else:
    28                     field.process(formdata)
    29             
    30             执行每个字段的process方法,为字段的data和字段的raw_data赋值
    31             def process(self, formdata, data=unset_value):
    32                 self.process_errors = []
    33                 if data is unset_value:
    34                     try:
    35                         data = self.default()
    36                     except TypeError:
    37                         data = self.default
    38         
    39                 self.object_data = data
    40         
    41                 try:
    42                     self.process_data(data)
    43                 except ValueError as e:
    44                     self.process_errors.append(e.args[0])
    45         
    46                 if formdata:
    47                     try:
    48                         if self.name in formdata:
    49                             self.raw_data = formdata.getlist(self.name)
    50                         else:
    51                             self.raw_data = []
    52                         self.process_formdata(self.raw_data)
    53                     except ValueError as e:
    54                         self.process_errors.append(e.args[0])
    55         
    56                 try:
    57                     for filter in self.filters:
    58                         self.data = filter(self.data)
    59                 except ValueError as e:
    60                     self.process_errors.append(e.args[0])
    61                 
    62         d. 页面上执行print(form.name) 时,打印标签
    63             
    64             因为执行了:
    65                 字段的 __str__ 方法
    66                 字符的 __call__ 方法
    67                 self.meta.render_field(self, kwargs)
    68                     def render_field(self, field, render_kw):
    69                         other_kw = getattr(field, 'render_kw', None)
    70                         if other_kw is not None:
    71                             render_kw = dict(other_kw, **render_kw)
    72                         return field.widget(field, **render_kw)
    73                 执行字段的插件对象的 __call__ 方法,返回标签字符串
    View Code

    2、验证流程分析

     1 a. 执行form的validate方法,获取钩子方法
     2             def validate(self):
     3                 extra = {}
     4                 for name in self._fields:
     5                     inline = getattr(self.__class__, 'validate_%s' % name, None)
     6                     if inline is not None:
     7                         extra[name] = [inline]
     8         
     9                 return super(Form, self).validate(extra)
    10         b. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数)
    11             def validate(self, extra_validators=None):
    12                 self._errors = None
    13                 success = True
    14                 for name, field in iteritems(self._fields):
    15                     if extra_validators is not None and name in extra_validators:
    16                         extra = extra_validators[name]
    17                     else:
    18                         extra = tuple()
    19                     if not field.validate(self, extra):
    20                         success = False
    21                 return success
    22         c. 每个字段进行验证时候
    23             字段的pre_validate 【预留的扩展】
    24             字段的_run_validation_chain,对正则和字段的钩子函数进行校验
    25             字段的post_validate【预留的扩展】
    View Code

    二、自定义Form组件

     
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    from flask import Flask,render_template,request,Markup
    app = Flask(__name__,template_folder="templates")
    app.debug = True
    # ==============通过这几个类就可以显示了-==============
    #插件
    class Widget(object):
        pass
    
    class InputText(Widget):
        def __call__(self, *args, **kwargs):
    
            return "<input type='text' name='name'>"
    
    class TextArea(Widget):
        def __call__(self, *args, **kwargs):
            return Markup("<textarea name='email'></textarea>")
    
    #Form
    class BaseForm(object):
        def __init__(self):
            #获取当前所有的字段
            _fields = {}
            for name, field in self.__class__.__dict__.items():
                if isinstance(field, Field):  # 筛选出字段是name和emailDe
                    _fields[name] = field
            self._fields = _fields
            self.data = {}
            # print(_fields)  # {'name': 111, 'email': 222}
    
        def validate(self,request_data):
            #先找到所有的字段,在执行每一个字段的validate方法
            flag = True
            for name, field in self._fields.items():
                input_val = request_data.get(name,"") #用户输入的值
                result= field.validate(input_val)  #每一个字段自己校验
                print("???????????",input_val,result)
                if not result:
                    flag = False
                else:
                    self.data[name] = input_val
            return flag
    #字段
    class Field(object):
        '''所有类的基类'''
        def __str__(self):          #python中的静态字段通过类能找到,通过对象也能找到
            return Markup(self.widget())  #self就是StringField,self
    
    class StringField(Field):  #每个字段打印的时候都要去执行__str__,所以选择放在基类里面,自己没有就调用父类的
        widget = InputText()
        def validate(self,val):
            if val:
                return True
    
    class EmaliField(Field):
        widget = TextArea()
        reg = ".*@.*"
    
        def validate(self,val):
            import re
            print(re.match(self.reg,val),"************")
            if re.match(self.reg,val):
                return True
    
    
    # ===============使用===============
    class LoginForm(BaseForm):
        name = StringField()
        email = EmaliField()
    
    @app.route('/index', methods=["GET","POST"])
    def index():
        form = LoginForm()
        ret = form.validate(request.form)
        print("验证成功",ret)
        print("验证成功的值",form.data)
        # print(form.name)
        # print(form.email)
        return render_template("index.html",form=form)
    
    if __name__ == '__main__':
        app.run()
     
  • 相关阅读:
    呃,如何使 .NET 程序,在 64位 系统 中,以 32位 模式运行。
    [转载]Cortana 设计指导方针
    Could not load file or assembly System.Core, Version=2.0.5.0
    wpf中用户控件的属性重用
    浅谈AutoResetEvent的用法
    WPF异步载入图片,附带载入中动画
    WPFLoading遮层罩
    获取WPF的DataGrid控件中,是否存在没有通过错误验证的Cell
    WPF通过异常来验证用户输入
    WPF验证之——必填验证
  • 原文地址:https://www.cnblogs.com/abdm-989/p/14093879.html
Copyright © 2011-2022 走看看