zoukankan      html  css  js  c++  java
  • 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)
        """
    View Code

    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]
            """
    View Code

    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

    插件下载地址:猛击这里

  • 相关阅读:
    拷贝构造函数的参数类型必须是引用
    [设计模式] 23 访问者模式 visitor Pattern
    [设计模式] 20 状态模式 State Pattern
    [设计模式] 19 观察者模式 Observer Pattern
    [设计模式] 18 备忘录模式Memento Pattern
    [设计模式] 17 中介者模式 Mediator Pattern
    [设计模式] 16 迭代器模式 Iterator Pattern
    [设计模式] 15 解释器模式 Interpreter
    [设计模式] 21 策略模式 Strategy
    图灵測试,測的究竟是什么?
  • 原文地址:https://www.cnblogs.com/jasonwang-2016/p/6000071.html
Copyright © 2011-2022 走看看