Tornado 自定义Form,session实现方法
一. 自定义Tornado 验证模块
我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单验证功能,但是对于Tornado而言,就没有这功能,所以就需要我们来自己自定义form表单验证,而且这种方法正是Django里的form表单验证的实质内容,也帮我们在后面学习Django理解相关的源码。
写之前,我们必须知道form表单验证的实质是什么?
实质就是正则匹配
我们知道用户提交数据是通过post方式提交,所以我们重写post方法,并在post方法进行业务逻辑处理
- 获取用户提交的数据
- 将用户提交的数据和正则表达式匹配
写之前,我们必须知道form表单验证的实质是什么?
实质就是正则匹配
我们知道用户提交数据是通过post方式提交,所以我们重写post方法,并在post方法进行业务逻辑处理
- 获取用户提交的数据
- 将用户提交的数据和正则表达式匹配
class MainForm(object):
def __init__(self):
# 各种信息正则匹配规则
# 并且要求这里字段名和前端传来的name一致
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 check_valid(self, request):
flag = True
form_dict = self.__dict__ #获取类的普通字段和值
for key, regular in form_dict.items():
post_value = request.get_argument(key) #获取用户输入的值
# 让提交的数据 和 定义的正则表达式进行匹配
ret = re.match(regular, post_value)
print key,ret,post_value
if not ret:
flag = False #一旦有匹配不成功的,设置为False
return flag #post方法里根据这个返回值来决定给客户返回什么内容
class IndexHandler(BaseRequestHandler):
def get(self):
self.render('index.html')
def post(self,*args,**kwargs):
obj = MainForm()
obj.check_valid(self)
self.get_argument()
因此我们应将自定义form中的自定义字段根据不同的正则表达式拆分成跟自己属性相关的类,实例如下:
根据每个字段的特性,定义基础的字段,如字符串,邮件类型,整数类等
class InputText:
def __str__(self):
return '<input type="text" />' class InputPassword:
def __str__(self):
return '<input type="password" />' class StringField:
reg = "^\w+$"
def __init__(self,w=None):
self.w = w if w else InputText() def match(self):
pass def __str__(self):
return str(self.w)
基于基本的字段,定制基础form类
class IndexForm:
def __init__(self):
self.user = StringField()
self.pwd = StringField(w=InputPassword()) def is_valid(self,handler):#handler 为tornado中路由对应的处理类的实例化对象
flag = True
for k,v in self.__dict__.items():
# k="user" v="^\w+$" StringField对象
# k="pwd" v="^\w+$" EmailField对象
if type(v) == StringListField:
input_value = handler.get_arguments(k)
else:
input_value = handler.get_argument(k) result = v.match(input_value)
if not result:
flag = False
return flag
自定义Form完整式例如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import re class InputText:
def __str__(self):
return '<input type="text" />' class InputPassword:
def __str__(self):
return '<input type="password" />' class StringField:
reg = "^\w+$"
def __init__(self,w=None):
self.w = w if w else InputText() def match(self):
pass def __str__(self):
return str(self.w) class StringListField:
reg = "^\w+$"
def __init__(self):
pass def match(self):
pass class EmailField:
reg = "^\w+$"
def __init__(self):
pass class IndexForm:
def __init__(self):
self.user = StringField()
self.pwd = StringField(w=InputPassword()) def is_valid(self,handler):
flag = True
for k,v in self.__dict__.items():
# k="user" v="^\w+$" StringField对象
# k="pwd" v="^\w+$" EmailField对象
if type(v) == StringListField:
input_value = handler.get_arguments(k)
else:
input_value = handler.get_argument(k) result = v.match(input_value)
if not result:
flag = False
return flag class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs):
form = IndexForm()
self.render('index.html', form=form) def post(self, *args, **kwargs):
form = IndexForm()
ret = form.is_valid(self)
print(ret) settings = {
'template_path': 'views'
} application = tornado.web.Application([
(r"/index.html", IndexHandler), ], **settings) if __name__ == "__main__": print('http://127.0.0.1:8005')
application.listen(8005)
tornado.ioloop.IOLoop.instance().start()
基于tornado自定义Form开发实践
通过以上的实例我们再来看下Tyrion开源的自定制Form 是如何开发的
1.首先定义一个基础的Field类
import re
from Tyrion import Widget
from Tyrion.Framework import FrameworkFactory class Field:
"""
所有Form字段的基类
""" def __init__(self, widget):
self.status = False
self.name = None
self.value = None
self.error = None
self.widget = widget def valid(self, handler):
"""
字段必须实现该方法,用于从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
raise NotImplementedError('your class %s must implement valid method' % self.__class__) def __str__(self): if self.value == None:
return str(self.widget) if isinstance(self.widget, Widget.SingleSelect):
self.widget.selected_value = self.value
elif isinstance(self.widget, Widget.MultiSelect):
self.widget.selected_value_list = self.value
elif isinstance(self.widget, Widget.InputSingleCheckBox):
self.widget.attr['checked'] = 'checked'
elif isinstance(self.widget, Widget.InputMultiCheckBox):
self.widget.checked_value_list = self.value
elif isinstance(self.widget, Widget.InputRadio):
self.widget.checked_value = self.value
elif isinstance(self.widget, Widget.TextArea):
self.widget.value = self.value
else:
self.widget.attr['value'] = self.value
return str(self.widget) def set_value(self, value):
self.value = value
Field
2.基于Field定义派生类如EmailField,IpField,IntegerField
class StringField(Field):
"""
字符串类字段
"""
REGULAR = "^.*$"
DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.max_length = max_length
self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(StringField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None)
# input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return ret = re.match(self.REGULAR, input_value)
if not ret:
if self.custom_error_dict.get('invalid', None):
self.error = self.custom_error_dict['invalid']
else:
self.error = "%s is invalid" % self.name
return if self.max_length:
if len(input_value) > self.max_length:
if self.custom_error_dict.get('max_length', None):
self.error = self.custom_error_dict['max_length']
else:
self.error = "%s max length is %s" % (self.name, self.max_length)
return if self.min_length: if len(input_value) < self.min_length:
if self.custom_error_dict.get('min_length', None):
self.error = self.custom_error_dict['min_length']
else:
self.error = "%s min length is %s" % (self.name, self.min_length)
return self.status = True class EmailField(Field):
"""
字符串类字段
"""
REGULAR = "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"
DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.max_length = max_length
self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(EmailField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
""" input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None)
# input_value = handler.get_argument(self.name, None) self.value = input_value
if not input_value:
if not self.required:
self.status = True
return
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return ret = re.match(self.REGULAR, input_value)
if not ret:
if self.custom_error_dict.get('invalid', None):
self.error = self.custom_error_dict['invalid']
else:
self.error = "%s is invalid" % self.name
return if self.max_length:
if len(input_value) > self.max_length:
if self.custom_error_dict.get('max_length', None):
self.error = self.custom_error_dict['max_length']
else:
self.error = "%s max length is %s" % (self.name, self.max_length)
return if self.min_length:
if len(input_value) < self.max_length:
if self.custom_error_dict.get('min_length', None):
self.error = self.custom_error_dict['min_length']
else:
self.error = "%s min length is %s" % (self.name, self.min_length)
return self.status = True 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}$"
DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.max_length = max_length
self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(IPField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None)
# input_value = handler.get_argument(self.name, None) self.value = input_value
if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return ret = re.match(self.REGULAR, input_value)
if not ret:
if self.custom_error_dict.get('invalid', None):
self.error = self.custom_error_dict['invalid']
else:
self.error = "%s is invalid" % self.name
return if self.max_length:
if len(input_value) > self.max_length:
if self.custom_error_dict.get('max_length', None):
self.error = self.custom_error_dict['max_length']
else:
self.error = "%s max length is %s" % (self.name, self.max_length)
return if self.min_length:
if len(input_value) < self.max_length:
if self.custom_error_dict.get('min_length', None):
self.error = self.custom_error_dict['min_length']
else:
self.error = "%s min length is %s" % (self.name, self.min_length)
return self.status = True class IntegerField(Field):
"""
字符串类字段
"""
REGULAR = "^\d+$"
DEFAULT_WIDGET = Widget.InputText def __init__(self, max_value=None, min_value=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大值为10',
'min_length': '最小值度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.max_value = max_value
self.min_value = min_value widget = widget if widget else self.DEFAULT_WIDGET() super(IntegerField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None)
# input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return ret = re.match(self.REGULAR, input_value)
if not ret:
if self.custom_error_dict.get('invalid', None):
self.error = self.custom_error_dict['invalid']
else:
self.error = "%s is invalid" % self.name
return input_value = int(input_value)
self.value = input_value if self.max_value:
if input_value > self.max_value:
if self.custom_error_dict.get('max_value', None):
self.error = self.custom_error_dict['max_value']
else:
self.error = "%s max value is %s" % (self.name, self.max_value)
return if self.min_value:
if input_value < self.min_value:
if self.custom_error_dict.get('min_value', None):
self.error = self.custom_error_dict['min_value']
else:
self.error = "%s min value is %s" % (self.name, self.min_value)
return self.status = True class FloatField(Field):
"""
字符串类字段
"""
REGULAR = "^\d+(\.\d{1,2})?$"
DEFAULT_WIDGET = Widget.InputText def __init__(self, max_value=None, min_value=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大值为10',
'min_length': '最小值度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.max_value = max_value
self.min_value = min_value widget = widget if widget else self.DEFAULT_WIDGET() super(FloatField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None)
# input_value = handler.get_argument(self.name, None) self.value = input_value
if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return ret = re.match(self.REGULAR, input_value)
if not ret:
if self.custom_error_dict.get('invalid', None):
self.error = self.custom_error_dict['invalid']
else:
self.error = "%s is invalid" % self.name
return input_value = float(input_value)
self.value = input_value if self.max_value:
if input_value > self.max_value:
if self.custom_error_dict.get('max_value', None):
self.error = self.custom_error_dict['max_value']
else:
self.error = "%s max value is %s" % (self.name, self.max_value)
return if self.min_value:
if input_value < self.min_value:
if self.custom_error_dict.get('min_value', None):
self.error = self.custom_error_dict['min_value']
else:
self.error = "%s min value is %s" % (self.name, self.min_value)
return self.status = True class StringListField(Field):
"""
字符串类字段
"""
REGULAR = "^.*$"
DEFAULT_WIDGET = Widget.InputMultiCheckBox def __init__(self, ele_max_length=None, ele_min_length=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'element': '列表中的元素必须是字符串',
'ele_max_length': '最大长度为10',
'ele_min_length': '最小长度为1',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.ele_max_length = ele_max_length
self.ele_min_length = ele_min_length widget = widget if widget else self.DEFAULT_WIDGET() super(StringListField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_arguments(handler, self.name, [])
# input_value = handler.get_arguments(self.name) self.value = input_value if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return for value in input_value:
ret = re.match(self.REGULAR, value)
if not ret:
if self.custom_error_dict.get('element', None):
self.error = self.custom_error_dict['element']
else:
self.error = "element %s is invalid" % self.name
return if self.ele_max_length:
if len(value) > self.ele_max_length:
if self.custom_error_dict.get('ele_max_length', None):
self.error = self.custom_error_dict['ele_max_length']
else:
self.error = "element %s max length is %s" % (self.name, self.ele_max_length)
return if self.ele_min_length: if len(value) < self.ele_min_length:
if self.custom_error_dict.get('ele_min_length', None):
self.error = self.custom_error_dict['ele_min_length']
else:
self.error = "element %s min length is %s" % (self.name, self.ele_min_length)
return self.status = True class IntegerListField(Field):
"""
字符串类字段
"""
REGULAR = "^\d+$"
DEFAULT_WIDGET = Widget.InputMultiCheckBox def __init__(self, ele_max_value=None, ele_min_value=None, error=None, required=True, widget=None):
"""
:param error: 自定义错误信息
如:{
'required': '值为空时的错误提示',
'element': '列表中的元素必须是数字',
'ele_max_value': '最大值为x',
'ele_min_value': '最小值为x',
}
:param required: 是否必须
:param widget: 指定插件,用于生成HTML标签(默认生成Input标签)
:return:
"""
self.custom_error_dict = {}
if error:
self.custom_error_dict.update(error) self.required = required
self.ele_max_value = ele_max_value
self.ele_min_value = ele_min_value widget = widget if widget else self.DEFAULT_WIDGET() super(IntegerListField, self).__init__(widget) def valid(self, handler):
"""
从请求中获取用户输入的值并和规则进行比较
:param handler: Tornado处理请求的XXXHandler对象
:return:
"""
input_value = FrameworkFactory.get_framework().get_arguments(handler, self.name, [])
# input_value = handler.get_arguments(self.name)
self.value = input_value if not input_value:
if not self.required:
self.status = True
return if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % self.name
return success_value_list = []
for value in input_value:
ret = re.match(self.REGULAR, value)
if not ret:
if self.custom_error_dict.get('element', None):
self.error = self.custom_error_dict['element']
else:
self.error = "element %s is invalid" % self.name
return
value = int(value)
success_value_list.append(value) if self.ele_max_value:
if value > self.ele_max_value:
if self.custom_error_dict.get('ele_max_value', None):
self.error = self.custom_error_dict['ele_max_value']
else:
self.error = "element %s max value is %s" % (self.name, self.ele_max_value)
return if self.ele_min_value: if value < self.ele_min_value:
if self.custom_error_dict.get('ele_min_value', None):
self.error = self.custom_error_dict['ele_min_value']
else:
self.error = "element %s min value is %s" % (self.name, self.ele_min_value)
return self.value = success_value_list
self.status = True
基于Field定义派生字段相关的类
3.我们发现上面定义的子Field中包含widget,这个是根据不同的Filed的需求生成不同的html标签。具体代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*- class Input:
def __init__(self, attr=None):
"""
:param attr: 生成的HTML属性,如:{'id': '123'}
:return:
"""
self.attr = attr if attr else {} def __str__(self):
"""
使用对象时返回的字符串
:return:
"""
t = "<input %s />"
attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp)
tag = t % (''.join(attr_list))
return tag class InputText(Input):
def __init__(self, attr=None):
attr_dict = {'type': 'text'}
if attr:
attr_dict.update(attr)
super(InputText, self).__init__(attr_dict) class InputEmail(Input):
def __init__(self, attr=None):
attr_dict = {'type': 'email'}
if attr:
attr_dict.update(attr)
super(InputEmail, self).__init__(attr_dict) class InputPassword(Input):
def __init__(self, attr=None):
attr_dict = {'type': 'password'}
if attr:
attr_dict.update(attr)
super(InputPassword, self).__init__(attr_dict) class InputSingleCheckBox(Input):
def __init__(self, attr=None):
attr_dict = {'type': 'checkbox'}
if attr:
attr_dict.update(attr)
super(InputSingleCheckBox, self).__init__(attr_dict) def __str__(self):
"""
使用对象时返回的字符串
:return:
"""
t = "<input %s />"
attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp)
tag = t % (''.join(attr_list))
return tag class InputMultiCheckBox:
def __init__(self, attr=None, text_value_list=None, checked_value_list=None):
"""
:param attr: 生成的HTML属性,如:{'id': '123'}
:param text_value_list: 生成CheckBox的value和内容,如:
[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
:param checked_value_list: 被选中的checked_value_list,如:[2,3]
:return:
"""
attr_dict = {'type': 'checkbox'}
if attr:
attr_dict.update(attr)
self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else []
self.checked_value_list = checked_value_list if checked_value_list else [] def __str__(self):
"""
使用对象时返回的字符串
:return:
"""
tag_list = []
for item in self.text_value_list:
a = "<div><span>%s</span><span>%s</span></div>"
b = "<input %s />"
attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp)
attr_list.append("%s='%s' " % ('value', item['value']))
if item['value'] in self.checked_value_list:
attr_list.append("checked='checked' ")
input_tag = b % (''.join(attr_list))
c = a % (input_tag, item['text'], )
tag_list.append(c)
return ''.join(tag_list) class InputRadio:
def __init__(self, attr=None, text_value_list=None, checked_value=None):
"""
:param attr: 生成的HTML属性,如:{'id': '123'}
:param text_value_list: 生成CheckBox的value和内容,如:
[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
:param checked_value: 被选中的checked_value,如:2
:return:
"""
attr_dict = {'type': 'radio'}
if attr:
attr_dict.update(attr)
self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else []
self.checked_value = checked_value def __str__(self):
"""
使用对象时返回的字符串
:return:
"""
tag_list = []
for item in self.text_value_list:
a = "<div><span>%s</span><span>%s</span></div>"
b = "<input %s />"
attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp)
attr_list.append("%s='%s' " % ('value', item['value']))
if item['value'] == self.checked_value:
attr_list.append("checked='checked' ")
input_tag = b % (''.join(attr_list))
c = a % (input_tag,item['text'])
tag_list.append(c)
return ''.join(tag_list) class SingleSelect:
def __init__(self, attr=None, text_value_list=None, selected_value=None):
"""
:param attr: 生成的HTML属性,如:{'id': '123'}
:param text_value_list: 生成CheckBox的value和内容,如:
[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
:param selected_value: 被选中的checked_value,如:2
:return:
"""
attr_dict = {}
if attr:
attr_dict.update(attr)
self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else []
self.selected_value = selected_value def __str__(self):
"""
使用对象时返回的字符串
:return:
""" a = "<select %s>%s</select>" attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp) option_list = [] for item in self.text_value_list: if item['value'] == self.selected_value:
b = "<option selected='selected' value='%s'>%s</option>"
else:
b = "<option value='%s'>%s</option>"
option = b % (item['value'], item['text'],)
option_list.append(option) tag = a % (''.join(attr_list), ''.join(option_list)) return tag class MultiSelect:
def __init__(self, attr=None, text_value_list=None, selected_value_list=None):
"""
:param attr: 生成的Select标签的属性,如:{'id': '123'}
:param text_value_list: 生成CheckBox的value和内容,如:
[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
:param selected_value_list: selected_value_list,如:[2,3,4]
:return:
"""
attr_dict = {'multiple': 'multiple'}
if attr:
attr_dict.update(attr)
self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else []
self.selected_value_list = selected_value_list if selected_value_list else [] def __str__(self):
"""
使用对象时返回的字符串
:return:
""" a = "<select %s>%s</select>" attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp) option_list = []
for item in self.text_value_list:
if item['value'] in self.selected_value_list:
b = "<option selected='selected' value='%s'>%s</option>"
else:
b = "<option value='%s'>%s</option>"
option = b % (item['value'], item['text'],)
option_list.append(option) tag = a % (''.join(attr_list), ''.join(option_list))
return tag class TextArea:
def __init__(self, attr=None, value=""):
"""
:param attr: 生成的HTML属性,如:{'id': '123'}
:return:
"""
self.attr = attr if attr else {}
self.value = value def __str__(self):
"""
使用对象时返回的字符串
:return:
"""
t = "<textarea %s>%s</textarea>"
attr_list = []
for k, v in self.attr.items():
temp = "%s='%s' " % (k, v,)
attr_list.append(temp)
tag = t % (''.join(attr_list), self.value)
return tag
widget.py
下面是具体的使用方法:
使用文档
1、下载安装
pip install PyTyrion
2、配置WEB框架种类
由于Tyrion同时支持Tornado、Django、Flask、Bottle多个WEB框架,所有在使用前需要进行指定。
import Tyrion
Tyrion.setup('tornado')
# setup的参数有:tornado(默认)、django、bottle、flask
3、创建Form类
Form类用于提供验证规则、插件属性、错误信息等
from Tyrion.Forms import Form
from Tyrion.Fields import StringField
from Tyrion.Fields import EmailField class LoginForm(Form):
username = StringField(error={'required': '用户名不能为空'})
password = StringField(error={'required': '密码不能为空'})
email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})
4、验证用户请求
前端HTML代码:
<form method="POST" action="/login.html">
<div>
<input type="text" name="username">
</div>
<div>
<input type="text" name="password">
</div>
<div>
<input type="text" name="email">
</div> <input type="submit" value="提交">
</form>
用户提交数据时,在后台书写如下代码即可实现用户请求数据验证(Tornado示例):
class LoginHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('login.html') def post(self, *args, **kwargs):
form = LoginForm(self) ###### 检查用户输入是否合法 ######
if form.is_valid(): ###### 如果不合法,则输出错误信息 ######
print(form.error_dict)
else:
###### 如果合法,则输出用户输入的内容 ######
5、验证用户请求 && 生成HTML标签 && 保留上次输入内容 && 错误提示
Tyrion不仅可以验证用户请求,还可以生成自动创建HTML标签并且可以保留用户上次输入的内容。在HTML模板中调用Form类对象的字段即可,如(Tornado示例):
from Tyrion.Forms import Form
from Tyrion.Fields import StringField
from Tyrion.Fields import EmailField class LoginForm(Form):
username = StringField(error={'required': '用户名不能为空'})
password = StringField(error={'required': '密码不能为空'})
email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})
Form类
class LoginHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
form = LoginForm(self)
self.render('login.html', form=form) def post(self, *args, **kwargs):
form = LoginForm(self) print(form.is_valid())
print(form.error_dict)
print(form.value_dict) self.render('login.html', form=form)
处理请求
<form method="post" action="/login.html">
<div>
<!-- Form创建的标签 -->
{% raw form.username %} <!-- 错误信息 -->
<span>{{form.error_dict.get('username',"")}}</span>
</div>
<div>
{% raw form.password %}
<span>{{form.error_dict.get('password',"")}}</span>
</div>
<div>
{% raw form.email %}
<span>{{form.error_dict.get('email',"")}}</span>
</div>
<input type="submit" value="提交"/>
</form>
创建模板login.html
6、Form字段类型
Form的字段用于指定从请求中获取的数据类型以及格式,以此来验证用户输入的内容。
from Tyrion.Forms import Form
from Tyrion.Fields import StringField
from Tyrion.Fields import EmailField class LoginForm(Form):
username = StringField(error={'required': '用户名不能为空'})
password = StringField(error={'required': '密码不能为空'})
email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})
以上代码表示此Form类可以用于验证用户输入的内容,并且 username和password必须不能为空,email必须不能为空并且必须是邮箱格式。
目前支持所有字段:
StringField
"""
要求必须是字符串,即:正则^.*$ 参数:
required 布尔值,是否允许为空
max_length 整数,限制用户输入内容最大长度
min_length 整数,限制用户输入内容最小长度
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
widget 定制生成的HTML插件(默认InputText)
""" EmailField
"""
要求必须是邮箱格式的字符串 参数:
required 布尔值,是否允许为空
max_length 整数,限制用户输入内容最大长度
min_length 整数,限制用户输入内容最小长度
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
widget 定制生成的HTML插件(默认InputText)
""" IPField
"""
要求必须是IP格式 参数:
required 布尔值,是否允许为空
max_length 整数,限制用户输入内容最大长度
min_length 整数,限制用户输入内容最小长度
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_length': '最大长度为10',
'min_length': '最小长度为1',
}
widget 定制生成的HTML插件(默认InputText) """ IntegerField
"""
要求必须整数格式 参数:
required 布尔值,是否允许为空
max_value 整数,限制用户输入数字最大值
min_value 整数,限制用户输入数字最小值
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_value': '最大值为10',
'max_value': '最小值度为1',
}
widget 定制生成的HTML插件(默认InputText) """ FloatField
"""
要求必须小数格式 参数:
required 布尔值,是否允许为空
max_value 整数,限制用户输入数字最大值
min_value 整数,限制用户输入数字最小值
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'invalid': '格式错误时的错误提示',
'max_value': '最大值为10',
'max_value': '最小值度为1',
}
widget 定制生成的HTML插件(默认InputText)
""" StringListField
"""
用于获取请求中的多个值,且保证每一个元素是字符串,即:正则^.*$
如:checkbox或selct多选时,会提交多个值,用此字段可以将用户提交的值保存至列表 参数:
required 布尔值,是否允许为空
ele_max_length 整数,限制用户输入的每个元素内容最大长度
ele_min_length 整数,限制用户输入的每个元素内容最小长度
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'element': '列表中的元素必须是字符串',
'ele_max_length': '最大长度为10',
'ele_min_length': '最小长度为1',
}
widget 定制生成的HTML插件(默认InputMultiCheckBox,即:checkbox)
""" IntegerListField
"""
用于获取请求中的多个值,且保证每一个元素是整数
如:checkbox或selct多选时,会提交多个值,用此字段可以将用户提交的值保存至列表 参数:
required 布尔值,是否允许为空
ele_max_value 整数,限制用户输入的每个元素内容最大长度
ele_min_value 整数,限制用户输入的每个元素内容最小长度
error 字典,自定义错误提示,如:{
'required': '值为空时的错误提示',
'element': '列表中的元素必须是数字',
'ele_max_value': '最大值为x',
'ele_min_value': '最小值为x',
}
widget 定制生成的HTML插件(默认InputMultiCheckBox,即:checkbox)
"""
7、Form字段widget参数:HTML插件
HTML插件用于指定当前字段在生成HTML时表现的种类和属性,通过指定此参数从而实现定制页面上生成的HTML标签
from Tyrion.Forms import Form
from Tyrion.Fields import StringField
from Tyrion.Fields import EmailField from Tyrion.Widget import InputPassword class LoginForm(Form):
password = StringField(error={'required': '密码不能为空'},widget=InputPassword())
上述LoginForm的password字段要求用户输入必须是字符串类型,并且指定生成HTML标签时会创建为<input type='password' > 标签
目前支持所有插件:
InputText
"""
设置Form对应字段在HTML中生成input type='text' 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}
"""
InputEmail
"""
设置Form对应字段在HTML中生成input type='email' 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}
"""
InputPassword
"""
设置Form对应字段在HTML中生成input type='password' 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}
"""
TextArea
"""
设置Form对应字段在HTML中生成 textarea 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1'}
value 字符串,用于设置textarea标签中默认显示的内容
""" InputRadio
"""
设置Form对应字段在HTML中生成一系列 input type='radio' 标签(选择时互斥) 参数:
attr 字典,生成的HTML属性,如:{'class': 'c1'}
text_value_list 列表,生成的多个radio标签的内容和值,如:[
{'value':1, 'text': '男'},
{'value':2, 'text': '女'},
]
checked_value 整数或字符串,默认被选中的标签的value的值 示例:
from Tyrion.Forms import Form
from Tyrion.Fields import IntegerField from Tyrion.Widget import InputRadio class LoginForm(Form):
favor = IntegerField(error={'required': '爱好不能为空'},
widget=InputRadio(attr={'class': 'c1'},
text_value_list=[
{'value': 1, 'text': '男'},
{'value': 2, 'text': '女'}, ],
checked_value=2
)
)
上述favor字段生成的HTML标签为:
<div>
<span>
<input class='c1' type="radio" name="gender" value="1">
</span>
<span>男</span>
</div>
<div>
<span>
<input class='c1' type="radio" name="gender" value="2" checked='checked'>
</span>
<span>女</span>
</div>
""" InputSingleCheckBox
"""
设置Form对应字段在HTML中生成 input type='checkbox' 标签
参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1'}
""" InputMultiCheckBox
"""
设置Form对应字段在HTML中生成一系列 input type='checkbox' 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1'}
text_value_list 列表,生成的多个checkbox标签的内容和值,如:[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
checked_value_list 列表,默认选中的标签对应的value, 如:[1,3]
"""
SingleSelect
"""
设置Form对应字段在HTML中生成 单选select 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1'}
text_value_list 列表,用于指定select标签中的option,如:[
{'value':1, 'text': '北京'},
{'value':2, 'text': '上海'},
{'value':3, 'text': '广州'},
{'value':4, 'text': '重庆'},
]
selected_value 数字或字符串,默认被选中选项对应的值,如: 3
""" MultiSelect
"""
设置Form对应字段在HTML中生成 多选select 标签 参数:
attr 字典,指定生成标签的属性,如: attr = {'class': 'c1'}
text_value_list 列表,用于指定select标签中的option,如:[
{'value':1, 'text': '篮球'},
{'value':2, 'text': '足球'},
{'value':3, 'text': '乒乓球'},
{'value':4, 'text': '羽毛球'},
]
selected_value_list 列表,默认被选中选项对应的值,如:[2,3,4]
"""
8、动态初始化默认值
由于Form可以用于生成HTML标签,如果想要在创建标签的同时再为其设置默认值有两种方式:
- 静态,在插件参数中指定
- 动态,调用Form对象的 init_field_value 方法来指定
class InitValueForm(Form):
username = StringField(error={'required': '用户名不能为空'})
age = IntegerField(max_value=500,
min_value=0,
error={'required': '年龄不能为空',
'invalid': '年龄必须为数字',
'min_value': '年龄不能小于0',
'max_value': '年龄不能大于500'}) city = IntegerField(error={'required': '年龄不能为空', 'invalid': '年龄必须为数字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '广州'}])
) gender = IntegerField(error={'required': '请选择性别',
'invalid': '性别必须为数字'},
widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },
{'value': 2, 'text': '女', }],
checked_value=2)) protocol = IntegerField(error={'required': '请选择协议', 'invalid': '协议格式错误'},
widget=InputSingleCheckBox(attr={'value': 1})) favor_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ])) favor_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ])) select_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ])) select_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
动态初始值 - Form类
class InitValueHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs):
form = InitValueForm(self) init_dict = {
'username': 'seven',
'age': 18,
'city': 2,
'gender': 2,
'protocol': 1,
'favor_int_val': [1, 3],
'favor_str_val': ['1', '3'],
'select_int_val': [1, 3],
'select_str_val': ['1', '3'] } # 初始化操作,设置Form类中默认值以及默认选项
form.init_field_value(init_dict) self.render('init_value.html', form=form)
动态初始值 - 处理请求的Handler(Tornado)
9、更多示例
示例源码下载:猛击这里
a. 基本使用
class RegisterForm(Form):
username = StringField(max_length=32,
min_length=6,
error={'required': '用户名不能为空',
'min_length': '用户名不能少于6位',
'max_length': '用户名不能超过32位'}) password = StringField(max_length=32,
min_length=6,
error={'required': '密码不能为空'},
widget=InputPassword()) gender = IntegerField(error={'required': '请选择性别',
'invalid': '性别必须为数字'},
widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },
{'value': 2, 'text': '女', }],
checked_value=2)) age = IntegerField(max_value=500,
min_value=0,
error={'required': '年龄不能为空',
'invalid': '年龄必须为数字',
'min_value': '年龄不能小于0',
'max_value': '年龄不能大于500'}) email = EmailField(error={'required': '邮箱不能为空',
'invalid': '邮箱格式错误'}) city = IntegerField(error={'required': '城市选项不能为空', 'invalid': '城市选项必须为数字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '广州'}])
)
protocol = IntegerField(error={'required': '请选择协议', 'invalid': '协议格式错误'},
widget=InputSingleCheckBox(attr={'value': 1})) memo = StringField(required=False,
max_length=150,
error={'invalid': '备注格式错误', 'max_length': '备注最大长度为150字'},
widget=TextArea())
registerForm
b. 多选checkbox
class MultiCheckBoxForm(Form):
favor_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ])) favor_str_val_default = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ],
checked_value_list=['1', '4'])) favor_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ])) favor_int_val_default = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ],
checked_value_list=[2, ]))
MultiCheckBoxForm
c、多选select
class MultiSelectForm(Form):
select_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ])) select_str_val_default = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ],
selected_value_list=['1', '3'])) select_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ])) select_int_val_default = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ],
selected_value_list=[2]))
MultiSelectForm
d. 动态select选项
class DynamicSelectForm(Form):
city = IntegerField(error={'required': '年龄不能为空', 'invalid': '年龄必须为数字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '广州'}])
) multi_favor = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ])) def __init__(self, *args, **kwargs):
super(DynamicSelectForm, self).__init__(*args, **kwargs) # 获取数据库中的最新数据并显示在页面上(每次创建对象都执行一次数据库操作来获取最新数据)
self.city.widget.text_value_list = [{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '南京'},
{'value': 4, 'text': '广州'}] self.multi_favor.widget.text_value_list = [{'value': 1, 'text': '篮球'},
{'value': 2, 'text': '足球'},
{'value': 3, 'text': '乒乓球'},
{'value': 4, 'text': '羽毛球'},
{'value': 5, 'text': '玻璃球'}]
DynamicSelectForm
三.自定义Session
对Session来说Tornado是没有的
简单回顾下:
1、自动生成一段字符串
2、将字符串发送到客户端的浏览器,同时把字符串当做key放在session里。(可以理解为session就是一个字典)
3、在用户的session对应的value里设置任意值
操作session
- 获取session:request.session[key]
- 设置session:reqeust.session[key] = value
- 删除session:del request[key]
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
2、上面是Django的原理是一样的,那么我们来自己写一个Session
2.1、储备知识点
#!/usr/bin/env python
# -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key):
print '__getitem__',key def __setitem__(self, key, value):
print '__setitem__',key,value def __delitem__(self, key):
print '__delitem__',key
2.2、应用工厂方法模式定义session保存的位置,用户只需在配置文件修改即可
class SessionHandler:
def initialize(self):
self.session_obj = SessionFacotory.get_session_obj(self) class SessionFacotory:
@staticmethod
def get_session_obj(handler):
if conf.session_type == 'redis':
return RedisSession(handler)
elif conf.session_type == 'memcache':
return RedisSession(handler)
else:
return MemorySession(handler)
2.3.缓存session
class CacheSession:
session_container = {}
session_id = "__sessionId__" def __init__(self, handler):
self.handler = handler
client_random_str = handler.get_cookie(CacheSession.session_id, None)
if client_random_str and client_random_str in CacheSession.session_container:
self.random_str = client_random_str
else:
self.random_str = create_session_id()
CacheSession.session_container[self.random_str] = {} expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key):
ret = CacheSession.session_container[self.random_str].get(key, None)
return ret def __setitem__(self, key, value):
CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key):
if key in CacheSession.session_container[self.random_str]:
del CacheSession.session_container[self.random_str][key]
CacheSession
2.4. memcache session
import memcache conn = memcache.Client(['192.168.11.119:12000'], debug=True, cache_cas=True) class MemcachedSession:
session_id = "__sessionId__" def __init__(self, handler):
self.handler = handler
# 从客户端获取随机字符串
client_random_str = handler.get_cookie(CacheSession.session_id, None)
# 如果从客户端获取到了随机字符串
#
if client_random_str and conn.get(client_random_str):
self.random_str = client_random_str
else:
self.random_str = create_session_id()
conn.set(self.random_str, json.dumps({}), config.SESSION_EXPIRES)
#CacheSession.session_container[self.random_str] = {} conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES) expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(MemcachedSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key):
# ret = CacheSession.session_container[self.random_str].get(key, None)
ret = conn.get(self.random_str)
ret_dict = json.loads(ret)
result = ret_dict.get(key,None)
return result def __setitem__(self, key, value):
ret = conn.get(self.random_str)
ret_dict = json.loads(ret)
ret_dict[key] = value
conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES) # CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key):
ret = conn.get(self.random_str)
ret_dict = json.loads(ret)
del ret_dict[key]
conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES)
MemcachedSession
2.5 redis session
import redis pool = redis.ConnectionPool(host='192.168.11.119', port=6379)
r = redis.Redis(connection_pool=pool) class RedisSession:
session_id = "__sessionId__" def __init__(self, handler):
self.handler = handler
# 从客户端获取随机字符串
client_random_str = handler.get_cookie(CacheSession.session_id, None)
# 如果从客户端获取到了随机字符串
if client_random_str and r.exists(client_random_str):
self.random_str = client_random_str
else:
self.random_str = create_session_id()
r.hset(self.random_str,None,None) # conn.set(self.random_str, json.dumps({}), config.SESSION_EXPIRES)
# CacheSession.session_container[self.random_str] = {}
r.expire(self.random_str, config.SESSION_EXPIRES)
# conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES) expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(RedisSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key):
# ret = CacheSession.session_container[self.random_str].get(key, None)
result = r.hget(self.random_str,key)
if result:
ret_str = str(result, encoding='utf-8')
try:
result = json.loads(ret_str)
except:
result = ret_str
return result
else:
return result def __setitem__(self, key, value):
if type(value) == dict:
r.hset(self.random_str, key, json.dumps(value))
else:
r.hset(self.random_str, key, value) # CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key):
r.hdel(self.random_str,key)
RedisSession
tornado cookie
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。定义于RFC2109和2965都已废弃,最新取代的规范是RFC6265。(可以叫做浏览器缓存)
1、cookie的基本操作
#!/usr/bin/env python
# -*- coding:utf-8 -*- import tornado.ioloop
import tornado.web class MainHandler(tornado.web.RequestHandler):
def get(self):
print(self.cookies) # 获取所有的cookie
self.set_cookie('k1','v1') # 设置cookie
print(self.get_cookie('k1')) # 获取指定的cookie
self.write("Hello, world") application = tornado.web.Application([
(r"/index", MainHandler),
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
2、加密cookie(签名)
Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:
#!/usr/bin/env python
# -*- coding:utf-8 -*- import tornado.ioloop
import tornado.web class MainHandler(tornado.web.RequestHandler):
def get(self):
if not self.get_secure_cookie("mycookie"): # 获取带签名的cookie
self.set_secure_cookie("mycookie", "myvalue") # 设置带签名的cookie
self.write("Your cookie was not set yet!")
else:
self.write("Your cookie was set!")
application = tornado.web.Application([
(r"/index", MainHandler),
]) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
签名Cookie的本质是:
写cookie过程: 将值进行base64加密
对除值以外的内容进行签名,哈希算法(无法逆向解析)
拼接 签名 + 加密值 读cookie过程: 读取 签名 + 加密值
对签名进行验证
base64解密,获取值内容
3.JavaScript操作Cookie
/*
设置cookie,指定秒数过期,
name表示传入的key,
value表示传入相对应的value值,
expires表示当前日期在加5秒过期
*/ function setCookie(name,value,expires){
var temp = [];
var current_date = new Date();
current_date.setSeconds(current_date.getSeconds() + 5);
document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}
tornado上传文件
上传文件这块可以分为两大类,第一类是通过form表单验证进行上传,还有一类就是通过ajax上传,下面就来介绍一下这两类
1、form表单上传文件
import tornado.web
import tornado.ioloop
import os class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('index.html') def post(self, *args, **kwargs):
file_metas = self.request.files["filename"] # 获取文件信息
for meta in file_metas:
file_name = meta['filename'] # 获得他的文件名字
file_names = os.path.join('static','img',file_name)
with open(file_names,'wb') as up: # 打开本地一个文件
up.write(meta['body']) # body就是文件内容,把他写到本地 settings = {
'template_path':'views',
'static_path':'static',
'static_url_prefix': '/statics/',
} application = tornado.web.Application([
(r'/index',IndexHandler)
],**settings) if __name__ == '__main__':
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
app.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/index" method="post" enctype="multipart/form-data">
<input type="file" name = "filename">
<input type="submit" value="提交">
</form>
</body>
</html>
index.html
2、ajax上传文件
“伪装ajax” iframe上传
<iframe id="my_iframe" name="my_iframe" style="display: none" src=""></iframe> <form id="fo" method="POST" action="/upload/" enctype="multipart/form-data">
<input type="text" id="user" name="user" />
<input type="file" id="img" name="img" onchange="uploadFile3();" />
<input type="submit" />
</form> ##Js
function uploadFile3(){
$('#container').find('img').remove();
document.getElementById('my_iframe').onload = callback;
document.getElementById('fo').target = 'my_iframe';
document.getElementById('fo').submit();
}
function callback(){
var text = $('#my_iframe').contents().find('body').text();
var json_data = JSON.parse(text);
console.log(json_data);
if(json_data.status){
// 已经上传成功
// 预览,创建image标签,src指向刚上传的静态文件路径
var tag = document.createElement('img');
tag.src = "/" + json_data.data;
tag.className = 'img';
$('#container').append(tag);
}else{
alert(json_data.error);
}
}
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="file" id="img" />
<input type="button" onclick="UploadFile();" value="提交"/> <script src="/statics/jquery-1.12.4.js"></script>
<script>
function UploadFile(){
var fileObj = $("#img")[0].files[0];
var form = new FormData();
form.append("filename", fileObj); $.ajax({
type:'POST',
url: '/index',
data: form,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function(arg){
console.log(arg);
}
})
}
</script>
</body>
</html>
jQuery上传
<input type="file" id="img" name="img" onchange="uploadFile3();" />
<a onclick="uploadFile1();" >XMLHttpRequet上传</a> function uploadFile1(){
// 创建表单对象
var form = new FormData();
// 在表单对象中添加:user: 用户输入的用户名
form.append('user',document.getElementById('user').value);
// 在表单对象中添加:img: 文件对象
var fileObj = document.getElementById("img").files[0];
form.append("img", fileObj); var xhr = new XMLHttpRequest();
// 回调函数,当Ajax请求状态变化时,自动触发
xhr.onreadystatechange = function(){
// xhr.readyState=4 表示,客户端已经将服务器端响应的内容全部获取完毕
if(xhr.readyState == 4){
// xhr.responseText 获取服务器端响应的文本内容,即: views中 return HttpResponse中的内容
var data = xhr.responseText;
console.log(data);
}
};
// 创建异步连接
xhr.open("post", '/upload/', true);
// 发送请求,将form中的数据发送到服务器端
xhr.send(form);
}
XML上传
tornado 生成随机验证码
用python生成随机验证码需要借鉴一个插件,和一个io模块,实现起来也非常容易,当然也需要借鉴session来判断验证码是否错误,下面写一段用户登录验证带验证码的,再看下效果,插件必须和执行文件必须放在更目录下
import io
import datetime
import json
from backend.utils import check_code
from forms import account
from backend.utils.response import BaseResponse
from backend import commons
from models import chouti_orm as ORM
from sqlalchemy import and_, or_ create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest() class SessionFactory: @staticmethod
def get_session_obj(handler):
obj = None if config.SESSION_TYPE == "cache":
obj = CacheSession(handler)
elif config.SESSION_TYPE == "memcached":
obj = MemcachedSession(handler)
elif config.SESSION_TYPE == "redis":
obj = RedisSession(handler)
return obj class CacheSession:
session_container = {}
session_id = "__sessionId__" def __init__(self, handler):
self.handler = handler
client_random_str = handler.get_cookie(CacheSession.session_id, None)
if client_random_str and client_random_str in CacheSession.session_container:
self.random_str = client_random_str
else:
self.random_str = create_session_id()
CacheSession.session_container[self.random_str] = {} expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key):
ret = CacheSession.session_container[self.random_str].get(key, None)
return ret def __setitem__(self, key, value):
CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key):
if key in CacheSession.session_container[self.random_str]:
del CacheSession.session_container[self.random_str][key] class BaseRequestHandler(tornado.web.RequestHandler): def initialize(self): self.session = SessionFactory.get_session_obj(self) class CheckCodeHandler(BaseRequestHandler):
def get(self, *args, **kwargs):
stream = io.BytesIO()
img, code = check_code.create_validate_code()
img.save(stream, "png")
self.session["CheckCode"] = code
self.write(stream.getvalue())
CheckCode
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>验证码</title>
</head>
<body>
<form action="/login" method="post">
<p>用户名: <input type="text" name="username"> </p>
<p>密码: <input type="password" name="password"> </p>
<p>验证码: <input type="text" name="code"><img src="/check_code" onclick="ChangeCode();" id = "checkcode"></p>
<input type="submit" value="submit"> <span>{{state}}</span>
</form>
<script type="text/javascript"> //当点击图片的时候,会刷新图片,这一段代码就可以实现
function ChangeCode() {
var code = document.getElementById('checkcode');
code.src += "?";
}
</script>
</body>
</html>
login.html
插件下载地址:猛击这里
Tornado 自定义Form,session实现方法的更多相关文章
- tornado自定义实现django include方法
tornado自定义实现django include方法 自定义URLmethod模块 from Custom.errors import * def include(base_url, expan ...
- Tornado自定义分布式session框架
一.session框架处理请求执行的流程: 1.服务器端生成随机的cookie字符串 2.浏览器发送请求,服务器将cookie返回给浏览器. 3.服务器在生成一个字典.字典的key为cookie,va ...
- 基于redis的处理session的方法
一个基于redis的处理session的方法,如下. <?php class Session_custom { private $redis; // redis实例 private $prefi ...
- tornado 自定义session (一)
tornado 中没有session功能,需要我们自己实现. 目录: settings: settings = { 'template_path': 'templates', 'static': 's ...
- Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session框架
Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session import tornado.ioloop import tornado.web from myhas ...
- 利用 ajax自定义Form表单的提交方式
需求场景:有时候单纯的form表单无法向后端传递额外的参数 比如需要action传递js异步生成的参数 ,form表单默认的action就无法满足需求,这时就需要我们自定义form表单的提交方式. h ...
- python26:自定义form表单验证
一.自定义Form的原理 1.1 各种form表单验证比较 只有python提供了form表单验证,其他的都没有提供.django提供的功能还不够强大.最强大的是微软的ASP.NET!我们可以自己写一 ...
- web前端框架之自定义form表单验证
自定义form验证初试 .在后端创建一个类MainForm,并且在类中自定义host ip port phone等,然后写入方法,在post方法中创建MainForm对象,并且把post方法中的sel ...
- 仿照wtform自定义Form组件
仿照wtforms自定义Form组件 1.wtforms 点击查看源码分析及使用方法 2.自定义Form组件 #!usr/bin/env python # -*- coding:utf-8 -*- f ...
随机推荐
- mysql远程连接授权
Mysql:is not allowed to connect to this MySQL server 如果你想连接你的mysql的时候发生这个错误: ERROR 1130: Host '192.1 ...
- Oracle的优化器的RBO和CBO方式
1.基于规则的优化方式(Rule-Based Optimization,简称为RBO) 优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则,对数据是不敏感的.它只借助少 ...
- Struts2_day04--课程介绍_Struts2拦截器概述&底层原理_重要的概念
Struts2_day04 上节内容 今天内容 Struts2拦截器概述 拦截器底层原理 重要的概念 自定义拦截器 自定义登录拦截器 Struts2的标签库 Struts2表单标签(会用) Strut ...
- 如何优化JAVA代码及提高执行效率
可供程序利用的资源(内存.CPU时间.网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定的任务.优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率.本文讨论的主要是如何提高代 ...
- 【BZOJ1706】[usaco2007 Nov]relays 奶牛接力跑 矩阵乘法
[BZOJ1706][usaco2007 Nov]relays 奶牛接力跑 Description FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项 ...
- Windows 2012 Server评估版本安装问题处理
由于工作需要,在微软官方网站下载了一个Windows2012评估版本,地址:http://technet.microsoft.com/zh-cn/evalcenter/hh670538.aspx 在通 ...
- CH5301 石子合并【区间dp】
5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆, ...
- oracle常用操作命令总结
一. 默认安装带来的用户名/密码:--sys/change_on_install SYSDBA 或 SYSOPER 不能以 NORMAL 登录,可作为默认的系统管理员 --system/安装时输入的密 ...
- c#修改cpu主频
并不是真正能修改硬件,只是一个数据,能骗过部分程序检测,如英雄联盟必须达到3.0的主频才能使用录像功能,通过修改可以达到要求. 下面是代码: public enum RegValueKind { // ...
- PHP 创建中文目录的情况
因为一个作业需要创建一些中文的目录,其实主要还是考虑一下编码问题. 首先确认下系统环境是什么编码,如果是gbk或者GB2312那就需要转下码,还有些特殊字符,就需要有个特殊的写法. iconv('UT ...