一、自定义Form的原理

1.1 各种form表单验证比较

只有python提供了form表单验证,其他的都没有提供。django提供的功能还不够强大。最强大的是微软的ASP.NET!我们可以自己写一个来实现。

1.2 【不推荐】通过request.post获取用户输入内容

用户输入表单==>用户输入的检测

1)我们之前是创建一个form类

2)用户提交表单,我们通过request.post拿到数据,然后封装到Form(数据)里面

3)obj.is_valid方法,来检查用户输入的内容,跟Form()定义的,是否匹配。

问题:

request.post 获取用户输入的内容,它知道用户输入了几个吗?

1.3 【推荐】通过自定义Form类,通过类对象来获取

1.3.1如何获取类的所有静态字段:

所以,通过request.post取数据不好,所以我们可以用form类。

如:

Form类:

u = xxxx

p = xxxx

我们先创建一个Form对象:

obj = Form()

for i in Form类中的所有东西:

问题:

Form类:这些都是静态字段,静态字段属于类。

如何获取一个类的所有静态字段?

'''

这些静态属性是属于类的

这就是通过打印类的字典,来获取类的静态属性

'''

class Foo(object):

p=123

u=456

print Foo.__dict__

# 如果要循环就是循环类的所有东西:

# for k,v in Foo类的所有东西:

'''

打印结果:

{'__module__': '__main__', 'p': 123, 'u': 456, '__dict__':

<attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}

'''

1.3.2 通过类对象来获取所有实例属性

'''

如果把属性写到初始化里,我们要找这些属性的话,就要找类的对象的字典了(这些属性属于类的实例)

'''

class Foo2(object):

def __init__(self):

self.u='wang'

self.p=123

# 如果要循环就是循环类的对象所有东西:

# for k,v in Foo2对象所有东西:

obj=Foo2()

print obj.__dict__

# 打印结果

# {'p': 123, 'u': wang}

# for k,v in 对象的所有东西:

1.3.3 自定义form验证原理(类对象获取对象属性)

'''

我们先定义一个类,类里面有多少字段,是我们程序员控制的。

我们可以根据Foo类来生成页面的标签!

用户提交数据的时候,我们先创建Foo类对象,然后再循环对象里所有的东西。

'''

#这里的obj为类的实例化对象

for k,v in obj.__dict__.iteritems():

print k,v   # k代表属性名:如'p', v代表值:如:123

# request.POST[k] # 如果循环,来获取request.POST[k],其实就是获取用户输入的数据

# 如果用户输入的是alex,request.POST[k]就等于alex

# 所以,我们通过循环自己的form来去前端取什么数据。是以我们在Form定义的项目为主,跟前端写多少没关系。

二、自定义Form实例1

2.1 获取用户输入的值

就是创建一个web程序,只要请求一进来,访问/index,其实就是访问MainHandler类的get方法或者post方法

目录结构如下:

运行:form_framework.py

浏览器访问:http://localhost:8888/index

这时,就执行了MainHandler类的get方法,就是渲染index.html页面

class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') def post(self, *args, **kwargs):
host = self.get_argument('host') # 在Tornado里,获得用户的输入,都是用get_argument
print host

  

重新运行:form_framework.py

然后输入:hostname内容,然后提交

此时python后台就打印:wang

2.2 自定义form类,打印对象的k,v

既然能获取单个属性,我们就可以循环form类对象来获取对象的所有属性(用户输入数据)

我们定义一个Form类,然后定义属性名(注意,跟form表单的name名要对应)

然后循环

class Form(object):
def __init__(self):
self.host = None
self.ip = None
self.port = None
self.phone = None class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') def post(self, *args, **kwargs):
# host = self.get_argument('host') # 在Tornado里,获得用户的输入,都是用get_argument
# print host
obj=Form()
for k,v in obj.__dict__.iteritems():
print k,v

现在后台打印:

ip None

host None

port None

phone None

我们可以通过自定义的form来获取用户提交的数据,如果index.html,多了一个地址栏,

<p>address: <input type="text" name="address" /> </p>

但是form类里没定义,我们也不管它。

也就是我们只收集form类定义的对象属性

加上:self.get_argument(k)

def post(self, *args, **kwargs):
# host = self.get_argument('host') # 在Tornado里,获得用户的输入,都是用get_argument
# print host
obj=Form()
for k,v in obj.__dict__.iteritems(): print k,v,self.get_argument(k) # 对象的k和值,用户输入的值(通过跟form表单里的name名对应)

此时再从浏览器输入表单内容,提交

python后台打印结果:

ip None 10.0.0.1

host None wang

port None 22

phone None 123456

没有address,因为我们不管它。这样就做到了,我们在Form类里写了哪些字段,就取用户输入的哪些数据。

2.3 用正则来验证用户输入数据

我们为啥要写Form类呢?因为要做验证!

k是字段,v是form对象的值,self.get_argument(k)是用户输入的值。

我们把v改成正则表达式,我们用正则来验证用户输入的值,如果验证成功,就代表合法的,不成功就不合法。

1)我们先改写Form类,把值改成正则表达式:

class Form(object):
def __init__(self):
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$'

然后我们,通过正则验证,如果循环过程,有一个验证不成功,flag=False,打印错误:

def post(self, *args, **kwargs):
# 在请求的时候,默认是验证成功的
flag= True
# host = self.get_argument('host') # 在Tornado里,获得用户的输入,都是用get_argument
# print host
obj=Form()
for k,v in obj.__dict__.iteritems():
# k,对象的字典
# v,对象中字段对应的值,正则
# self.get_argument(k),用户输入的值(通过跟form表单里的name名对应)
# 我们用正则来验证用户输入的值,如果验证成功,就代表合法的,不成功就不合法。
# print k,v,self.get_argument(k)
import re
if re.match(v,self.get_argument(k)): # 如果符合,则返回一个对象,如果不符合就返回一个None
pass
else:
flag = False # 在循环的过程中,一旦有一个不满足,就是false了。 if flag:
self.write('ok')
else:
self.write('error')

  

重启:form_framework.py

然后在表单输入错误的格式,提交后就返回error:

输入格式错误,返回:error

2.4 把验证写到form类里

因为必须从Form类里获取正则表达式,再做验证,所以,我们直接把验证写到Form类里,把MainHandler类的post只做主函数就行了。

1)首先把:or k,v in obj.__dict__.iteritems(): 移动到Form里,

这里的obj,就是Form的实例化对象,在Form里就是指self

class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') def post(self, *args, **kwargs):
# 在请求的时候,默认是验证成功的
flag= True
obj=Form()
#for k,v in obj.__dict__.iteritems(): #移动到Form类里
import re
if re.match(v,self.get_argument(k)): pass
else:
flag = False # 在循环的过程中,一旦有一个不满足,就是false了。 if flag:
self.write('ok')
else:
self.write('error') class Form(object):
def __init__(self):
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$'
def is_valid(self):
for k,v in self.__dict__.iteritems(): # 移动到这里,obj改成self
import re

2)传代码:if re.match(v,self.get_argument(k)):

看上面代码

if re.match(v,self.get_argument(k)):

post函数里的self,指的是MainHandler这个类的对象,

我们把is_valid函数传个参数,request,

在is_valid函数里改写代码为:if re.match(v,request.get_argument(k)):

其实这里的request就是:MainHandler对象,

is_valid函数在MainHandler里被调用,把自己的对象self传进去。

3)把flag=True,分别定义在两个函数里

改写后的代码如下:

class Form(object):
def __init__(self):
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$'
def is_valid(self):
# 在请求的时候,默认是验证成功的
flag= True
for k,v in self.__dict__.iteritems():
import re
import re
if re.match(v,self.get_argument(k)): # 如果符合,则返回一个对象,如果不符合就返回一个None
pass
else:
flag = False # 在循环的过程中,一旦有一个不满足,就是false了。 class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') def post(self, *args, **kwargs):
# host = self.get_argument('host') # 在Tornado里,获得用户的输入,都是用get_argument
# print host
flag= True
obj=Form()
obj.is_valid(self) # 把自己的类对象self传到MainHandler里。
if flag:
self.write('ok')
else:
self.write('error')

三、Form类优化

3.1 把is_valid放到基类里

在django里,每一个表单就是一个form,例如LoginForm,AssetForm。。。

在你创建很多form的时候,但是is_valid都一样。你需要在每个Form类里都写一遍吗?

不需要,你可以用基类。

class BaseForm(object):
def is_valid(self):
# 在请求的时候,默认是验证成功的
flag= True
for k,v in self.__dict__.iteritems():
import re
import re
if re.match(v,self.get_argument(k)): # 如果符合,则返回一个对象,如果不符合就返回一个None
pass
else:
flag = False # 在循环的过程中,一旦有一个不满足,就是false了。 class Form(BaseForm):
def __init__(self):
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$' class LoginForm(object):
def __init__(self):
self.name= "(.*)"

3.2 正则表达式分门别类

如果多个表单有同一个正则,例如ip地址,就会重复写同样正则了。

我们可以针对每个类型的验证,单独写正则表达式类。

调用的时候,调用这个字段的正则类的对象就行了。这样就提高重用性了。

class ValidateIpv4(object):
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') class ValidatePhone(object):
phone_re = re.compile(r'^1[3|4|5|8][0-9]\d{8}$') class Form(BaseForm):
def __init__(self):
self.host = "(.*)"
self.ip = ValidateIpv4.ipv4_re
self.port = '(\d+)'
self.phone = ValidatePhone.phone_re

  

  

3.3 验证后返回成功或失败信息

在django里,验证无论成功或者失败,都返回信息

对于IP来说,如果IP错误的话,也会有IP格式错误的提示。

在django中是这么做的:

from django import forms

import re
from django.core.exceptions import ValidationError def validate_ipv4(value): # ip地址 验证例如:10.1.6.10
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
if not ipv4_re.match(value): # 这里做了验证,如果不成功,则报错
raise ValidationError('IP段格式错误.') # ValidationError是django的方法 class AddressPoolForm(forms.Form):
getway = forms.CharField(validators=[validate_ipv4, ], # 验证ip地址
error_messages={'required': u'网关不能为空', 'invalid': u'网关格式错误'},
widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': '网关'}))

那在自定义的Form里怎么做呢?

那在自定义的Form里怎么做呢?

required的值是传进来的:

required:True  表示:字段必须要填,并且验证

required:False  表示:字段可填可不填,不做验证

假如,required是False,则不做验证,直接返回值。

如果required=True:则判断:如果没有自定义'required'和'valid'错误信息,则用默认的(Field提供)

如果验证成功,则返回正则匹配的内容。

import tornado.ioloop
import tornado.web
import re class Field(object):
def __init__(self, error_msg_dict, required):
self.id_valid = False
self.value = None
self.error = None
self.name = None
self.error_msg = error_msg_dict
self.required = required def match(self, name, value):
self.name = name if not self.required: # 假如,required是False,则不做验证,直接返回值。
self.id_valid = True
self.value = value
else:
if not value: # 假如用户没传值,则给出require报错信息:
if self.error_msg.get('required', None): # 先看有没有自定义的'required'错误信息,有就用自定义的,没有则用默认的。
self.error = self.error_msg['required']
else:
self.error = "%s is required" % name
else: # 如果用户传来值,则做验证,如果验证成功,则返回匹配结果,没成功,则返回自定义(优先级高)或默认信息
ret = re.match(self.REGULAR, value)
if ret:
self.id_valid = True # 是正则验证成功的标识
self.value = ret.group()
else: # 先看有没有自定义的'valid'错误信息,有就用自定义的,没有则用默认的。
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
else:
self.error = "%s is invalid" % name # 如果required=True:则判断:如果有自定义了'required'和'valid'错误,则用自定义的
class IPField(Field):
REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" def __init__(self, error_msg_dict=None, required=True):
error_msg = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
# 继承基类的__init__方法,同时,把参数(error_msg,required)传给基类__init__
super(IPField, self).__init__(error_msg_dict=error_msg, required=required)

说明:

class IPField(Field):里的:

# 外面传参:error_msg_dict 可以定制化错误信息!这里required默认值是True

def __init__(self, error_msg_dict=None, required=True):

        error_msg = {}  # {'required': 'IP不能为空', 'valid': 'IP格式错误'} 

        if error_msg_dict:

            error_msg.update(error_msg_dict) # 把定制化的错误信息来更新error_msg这个字典(也就是定制化错误优先级最高!)

# 这时候调用IPField,就可以随意传自定义的错误信息了!required=True是默认值,可以不用传

class Form(BaseForm):
def __init__(self):
# required=True是默认值,可以不用传
self.ip = IPField(error_msg_dict={'required': '我的IP不能为空', 'valid': '我的IP格式错误'})

python26:自定义form表单验证的更多相关文章

  1. web前端框架之自定义form表单验证

    自定义form验证初试 .在后端创建一个类MainForm,并且在类中自定义host ip port phone等,然后写入方法,在post方法中创建MainForm对象,并且把post方法中的sel ...

  2. tornado之自定义form表单验证

    直接上链接吧:银角的地址 源码下载链接:点我点我点我...

  3. 看用Tornado如何自定义实现表单验证

    我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单验证功能,但是对于Tornado而言, ...

  4. Django(5) session登录注销、csrf及中间件自定义、django Form表单验证(非常好用)

    一.Django中默认支持Session,其内部提供了5种类型的Session供开发者使用: 数据库(默认) 缓存 文件 缓存+数据库 加密cookie 1.数据库Session 1 2 3 4 5 ...

  5. python_way day19 HTML-day5 (form表单验证,CSRF,cookie,session,缓存)

    python-way day19 1. dJango的form表单验证 2.CSRF 跨站请求伪造 3.cookie,session 4.缓存 一,django表单验证功能 1.django验证基础: ...

  6. Day19 Django之Form表单验证、CSRF、Cookie、Session和Model操作

    一.Form表单验证 用于做用户提交数据的验证1.自定义规则 a.自定义规则(类,字段名==html中的name值)b.数据提交-规则进行匹配代码如下: """day19 ...

  7. [php基础]PHP Form表单验证:PHP form validator使用说明

    在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...

  8. Django中的Form表单验证

    回忆一下Form表单验证的逻辑: 前端有若干个input输入框,将用户输入内容,以字典传递给后端. 后端预先存在一个Form表单验证的基类,封装了一个检测用户输入是否全部通过的方法.该方法会先定义好错 ...

  9. ASP.NET MVC Form表单验证与Authorize特性

    一.Form表单验证 1.基本概念 表单验证是一个基于票据(ticket-based)[也称为基于令牌(token-based)]的系统.当用户登录系统以后,会得到一个包含基于用户信息的票据(tick ...

随机推荐

  1. [翻译]NUnit---SetUp and SetUpFixture and Suite Attributes(十九)

    SetUpAttribute (NUnit 2.0 / 2.5) 本特性用于TestFixture提供一个公共的功能集合,在呼叫每个测试方法之前执行.同时也用在SetUpFixture中,SetUpF ...

  2. bash基本命令速查表

    来源:https://github.com/skywind3000/awesome-cheatsheets/blob/master/languages/bash.sh ################ ...

  3. 解决EF没有生成字段和表说明

    找了很多资料,终于找到一篇真正能解决ef生成字段说明,注释的文章,收藏不了,于是转载 本文章为转载,原文地址 项目中使用了EF框架,使用的是Database-First方式,因为数据库已经存在,所以采 ...

  4. 附加属性来控制控件中,要扩展模块的visibility

    可解决: 文本框控件中的按钮,DataGridColumnHeader中加入Filter控件... cs文件中的 附加属性 + 样式文件中的 template+控件 -> visibility ...

  5. 667. Beautiful Arrangement II

    Given two integers n and k, you need to construct a list which contains n different positive integer ...

  6. jvm高级特性(4)(内存分配回收策略)

    JVM高级特性与实践(四):内存分配 与 回收策略 一. 内存分配 和 回收策略 1,对象内存分配的概念: 往大方向讲,它就是在堆上分配(但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配), ...

  7. 数据分析库Pandas

    Pandas介绍 导入pandas库 import pandas as pd 读取CSV文件 df = pd.read_csv('file_name') #注意文件路径 读取前几条数据 df.head ...

  8. Mac下使用zsh不执行/etc/profile文件

    Mac下使用了zsh会不执行/etc/profile文件,当然,如果用原始的是会执行. 转而执行的是这两个文件,每次登陆都会执行: ~/.zshrc与/etc/zshenv与/etc/zshrc 所以 ...

  9. 课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 2、10个测验题

    1.What does the analogy “AI is the new electricity” refer to?  (B) A. Through the “smart grid”, AI i ...

  10. Linux驱动:LCD驱动测试

    (1) 进入内核源码目录中,make menuconfig -> Device Drivers -> Graphics support -> [M]Support for frame ...