Flask 【第十篇】自定义Form组件

Stella981
• 阅读 655

一、wtforms源码流程

1、实例化流程分析

# 源码流程
    1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中
    2. 执行构造方法
        
        a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。
            即:
                _fields = {
                    name: wtforms.fields.core.StringField(),
                }
                
            PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField()
        
        b. 循环_fields,为对象设置属性
            for name, field in iteritems(self._fields):
                # Set all the fields to attributes so that they obscure the class
                # attributes with the same names.
                setattr(self, name, field)
        c. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs)
            优先级:obj,data,formdata;
            
            再循环执行每个字段的process方法,为每个字段设置值:
            for name, field, in iteritems(self._fields):
                if obj is not None and hasattr(obj, name):
                    field.process(formdata, getattr(obj, name))
                elif name in kwargs:
                    field.process(formdata, kwargs[name])
                else:
                    field.process(formdata)
            
            执行每个字段的process方法,为字段的data和字段的raw_data赋值
            def process(self, formdata, data=unset_value):
                self.process_errors = []
                if data is unset_value:
                    try:
                        data = self.default()
                    except TypeError:
                        data = self.default
        
                self.object_data = data
        
                try:
                    self.process_data(data)
                except ValueError as e:
                    self.process_errors.append(e.args[0])
        
                if formdata:
                    try:
                        if self.name in formdata:
                            self.raw_data = formdata.getlist(self.name)
                        else:
                            self.raw_data = []
                        self.process_formdata(self.raw_data)
                    except ValueError as e:
                        self.process_errors.append(e.args[0])
        
                try:
                    for filter in self.filters:
                        self.data = filter(self.data)
                except ValueError as e:
                    self.process_errors.append(e.args[0])
                
        d. 页面上执行print(form.name) 时,打印标签
            
            因为执行了:
                字段的 __str__ 方法
                字符的 __call__ 方法
                self.meta.render_field(self, kwargs)
                    def render_field(self, field, render_kw):
                        other_kw = getattr(field, 'render_kw', None)
                        if other_kw is not None:
                            render_kw = dict(other_kw, **render_kw)
                        return field.widget(field, **render_kw)
                执行字段的插件对象的 __call__ 方法,返回标签字符串

2、验证流程分析

a. 执行form的validate方法,获取钩子方法
            def validate(self):
                extra = {}
                for name in self._fields:
                    inline = getattr(self.__class__, 'validate_%s' % name, None)
                    if inline is not None:
                        extra[name] = [inline]
        
                return super(Form, self).validate(extra)
        b. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数)
            def validate(self, extra_validators=None):
                self._errors = None
                success = True
                for name, field in iteritems(self._fields):
                    if extra_validators is not None and name in extra_validators:
                        extra = extra_validators[name]
                    else:
                        extra = tuple()
                    if not field.validate(self, extra):
                        success = False
                return success
        c. 每个字段进行验证时候
            字段的pre_validate 【预留的扩展】
            字段的_run_validation_chain,对正则和字段的钩子函数进行校验
            字段的post_validate【预留的扩展】

二、自定义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()
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这