一、自定义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. python中list的sort方法

    转:https://www.cnblogs.com/zle1992/p/6271105.html 使用python对列表(list)进行排序,说简单也简单,说复杂也复杂,我一开始学的时候也搞不懂在说什 ...

  2. 【加密算法】AES

    一.简介 AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高. 用AES加密2000年10月,NIST(美国国家标准和技术协会 ...

  3. sqlserver插入之字符串+数字

    declare @i int,@a varchar(10)set @i = 0set @a='hiro--'+LTRIM(@i)while @i < 500begin insert into h ...

  4. Unity获取object所有属性的一个方法,一些界面上没有开放的属性可以用该方法编辑

    static void PrintProperty () { if(Selection.activeObject == null) return; SerializedObject so = new ...

  5. JQuery Mobile - 需要注意问题!

    一,JQuery Mobile 和 JQuery 版本对接,一定要选用和当前JQuery Mobile 对应版本的JQuery . 二,在台式机的模拟器和真机中的显示结果可能不一样.我在台式机中使用的 ...

  6. Debug Dart at External Terminal

    launch.json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions ...

  7. django 获取外键对应数据的方式

    模型 models.py中 from django.db import models class User(models.Model): name = models.CharField() class ...

  8. Gson简单使用

    最近做个IM类型的Android 应用,由于有三种客户端(pc,ios,Android),所以底层使用的是C++与服务器通信,所以通信部分基本上有c++完成,封装好Jni即可,可以把底层c++通信看成 ...

  9. day 52 Django 的中间件加载顺序

    前情提要: django的中间键的作用是进行加载 可以通过中间键进行辅助操作 1.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局 ...

  10. Centos7下CPU内存等资源监控

    1.查看内存使用情况: [root@takeout web-takeout]# free -m total used free shared buff/cache available Mem: 378 ...