zoukankan      html  css  js  c++  java
  • 自定义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()
  • 相关阅读:
    HDU 1525
    kmp模板
    hdu 4616 Game(树形DP)
    hdu 4619 Warm up 2(并查集活用)
    hdu 4614 Vases and Flowers(线段树加二分查找)
    Codeforces 400D Dima and Bacteria(并查集最短路)
    poj 2823 Sliding Window (单调队列)
    hdu 2196 Computer(树形dp)
    hdu 4604 Deque
    最短路径
  • 原文地址:https://www.cnblogs.com/morgana/p/8493261.html
Copyright © 2011-2022 走看看