python获得用户表单输入_python26:自定义form表单验证

一、自定义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__':

, '__weakref__': , '__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页面

classMainHandler(tornado.web.RequestHandler):defget(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名要对应)

然后循环

classForm(object):def __init__(self):

self.host=None

self.ip=None

self.port=None

self.phone=NoneclassMainHandler(tornado.web.RequestHandler):defget(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,多了一个地址栏,

address:  

但是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类,把值改成正则表达式:

classForm(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

classMainHandler(tornado.web.RequestHandler):defget(self):

self.render('index.html')def post(self, *args, **kwargs):#在请求的时候,默认是验证成功的

flag=True

obj=Form()#for k,v in obj.__dict__.iteritems(): #移动到Form类里

importreifre.match(v,self.get_argument(k)):pass

else:

flag= False #在循环的过程中,一旦有一个不满足,就是false了。

ifflag:

self.write('ok')else:

self.write('error')classForm(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}$'

defis_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,分别定义在两个函数里

改写后的代码如下:

classForm(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}$'

defis_valid(self):#在请求的时候,默认是验证成功的

flag=Truefor k,v in self.__dict__.iteritems():importreimportreif re.match(v,self.get_argument(k)): #如果符合,则返回一个对象,如果不符合就返回一个None

pass

else:

flag= False #在循环的过程中,一旦有一个不满足,就是false了。

classMainHandler(tornado.web.RequestHandler):defget(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里。

ifflag:

self.write('ok')else:

self.write('error')

三、Form类优化

3.1 把is_valid放到基类里

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

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

不需要,你可以用基类。

classBaseForm(object):defis_valid(self):#在请求的时候,默认是验证成功的

flag=Truefor k,v in self.__dict__.iteritems():importreimportreif re.match(v,self.get_argument(k)): #如果符合,则返回一个对象,如果不符合就返回一个None

pass

else:

flag= False #在循环的过程中,一旦有一个不满足,就是false了。

classForm(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}$'

classLoginForm(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 importformsimportrefrom django.core.exceptions importValidationErrordef 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的方法

classAddressPoolForm(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提供)

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

importtornado.ioloopimporttornado.webimportreclassField(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=requireddefmatch(self, name, value):

self.name=nameif not self.required: #假如,required是False,则不做验证,直接返回值。

self.id_valid =True

self.value=valueelse:if not value: #假如用户没传值,则给出require报错信息:

if self.error_msg.get('required', None): #先看有没有自定义的'required'错误信息,有就用自定义的,没有则用默认的。

self.error = self.error_msg['required']else:

self.error= "%s is required" %nameelse: #如果用户传来值,则做验证,如果验证成功,则返回匹配结果,没成功,则返回自定义(优先级高)或默认信息

ret =re.match(self.REGULAR, value)ifret:

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'错误,则用自定义的

classIPField(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格式错误'}

iferror_msg_dict:

error_msg.update(error_msg_dict)#继承基类的__init__方法,同时,把参数(error_msg,required)传给基类__init__

super(IPField, self).__init__(error_msg_dict=error_msg, required=required)

说明:

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

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

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

iferror_msg_dict:

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

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

classForm(BaseForm):def __init__(self):#required=True是默认值,可以不用传

self.ip = IPField(error_msg_dict={'required': '我的IP不能为空', 'valid': '我的IP格式错误'})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值