模型绑定有两个主要功能:
- 自动生成html表单
- 用户输入验证
在之前学习的Django中为程序员提供了非常便捷的模型绑定功能,但是在Tornado中,一切需要自己动手!!!
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <h1>Hello</h1> 9 <form action="/index" method="post"> 10 <p>hostname: <input type="text" name="host"></p> 11 <p>ip: <input type="text" name="ip"></p> 12 <p>port: <input type="text" name="port"></p> 13 <p>phone: <input type="text" name="phone"></p> 14 <input type="submit" value="提交"> 15 </form> 16 </body> 17 </html>
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.web 5 import tornado.ioloop 6 import re 7 8 class MainForm(object): 9 def __init__(self): 10 self.host = "(.*)" 11 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}$" 12 self.port = '(\d+)' 13 self.phone = '^1[3|4|5|8][0-9]\d{8}$' 14 15 def check_valid(self,handler): 16 form_dict = self.__dict__ 17 for key,regular in form_dict.items(): 18 post_value = handler.get_argument(key) 19 # 让提交的数据 和 定义的正则表达式进行匹配 20 ret = re.match(regular,post_value) 21 return ret 22 23 24 class MainHandler(tornado.web.RequestHandler): 25 def get(self,*args,**kwargs): 26 self.render('index.html') 27 28 def post(self, *args, **kwargs): 29 obj = MainForm() 30 result = obj.check_valid(self) 31 if result: 32 self.write('ok') 33 else: 34 self.redirect('/index') 35 36 settings = { 37 'template_path':'views', 38 # 'static_path':'static', 39 # 'static_url_prefix':'/static/', 40 'cookie_secret':'fasfsgsghdhdh', 41 'login_url':'/login' 42 } 43 44 application = tornado.web.Application([ 45 (r'/index',MainHandler), 46 ],**settings) 47 48 if __name__ == '__main__': 49 application.listen(8888) 50 tornado.ioloop.IOLoop.instance().start()
由于请求验证时,需要考虑是否可以为空以及正则表达式的复用,所以:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import tornado.ioloop 5 import tornado.web 6 import re 7 8 9 class Field(object): 10 11 def __init__(self, error_msg_dict, required): 12 self.id_valid = False 13 self.value = None 14 self.error = None 15 self.name = None 16 self.error_msg = error_msg_dict 17 self.required = required 18 19 def match(self, name, value): 20 self.name = name 21 22 if not self.required: 23 self.id_valid = True 24 self.value = value 25 else: 26 if not value: 27 if self.error_msg.get('required', None): 28 self.error = self.error_msg['required'] 29 else: 30 self.error = "%s is required" % name 31 else: 32 ret = re.match(self.REGULAR, value) 33 if ret: 34 self.id_valid = True 35 self.value = ret.group() 36 else: 37 if self.error_msg.get('valid', None): 38 self.error = self.error_msg['valid'] 39 else: 40 self.error = "%s is invalid" % name 41 42 43 class IPField(Field): 44 REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" 45 46 def __init__(self, error_msg_dict=None, required=True): 47 48 error_msg = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'} 49 if error_msg_dict: 50 error_msg.update(error_msg_dict) 51 52 super(IPField, self).__init__(error_msg_dict=error_msg, required=required) 53 54 55 class IntegerField(Field): 56 REGULAR = "^\d+$" 57 58 def __init__(self, error_msg_dict=None, required=True): 59 error_msg = {'required': '数字不能为空', 'valid': '数字格式错误'} 60 if error_msg_dict: 61 error_msg.update(error_msg_dict) 62 63 super(IntegerField, self).__init__(error_msg_dict=error_msg, required=required) 64 65 66 class CheckBoxField(Field): 67 68 def __init__(self, error_msg_dict=None, required=True): 69 error_msg = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'} 70 if error_msg_dict: 71 error_msg.update(error_msg_dict) 72 73 super(CheckBoxField, self).__init__(error_msg_dict=error_msg, required=required) 74 75 def match(self, name, value): 76 self.name = name 77 78 if not self.required: 79 self.id_valid = True 80 self.value = value 81 else: 82 if not value: 83 if self.error_msg.get('required', None): 84 self.error = self.error_msg['required'] 85 else: 86 self.error = "%s is required" % name 87 else: 88 if isinstance(name, list): 89 self.id_valid = True 90 self.value = value 91 else: 92 if self.error_msg.get('valid', None): 93 self.error = self.error_msg['valid'] 94 else: 95 self.error = "%s is invalid" % name 96 97 98 class FileField(Field): 99 REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$" 100 101 def __init__(self, error_msg_dict=None, required=True): 102 error_msg = {} # {'required': '数字不能为空', 'valid': '数字格式错误'} 103 if error_msg_dict: 104 error_msg.update(error_msg_dict) 105 106 super(FileField, self).__init__(error_msg_dict=error_msg, required=required) 107 108 def match(self, name, value): 109 self.name = name 110 self.value = [] 111 if not self.required: 112 self.id_valid = True 113 self.value = value 114 else: 115 if not value: 116 if self.error_msg.get('required', None): 117 self.error = self.error_msg['required'] 118 else: 119 self.error = "%s is required" % name 120 else: 121 m = re.compile(self.REGULAR) 122 if isinstance(value, list): 123 for file_name in value: 124 r = m.match(file_name) 125 if r: 126 self.value.append(r.group()) 127 self.id_valid = True 128 else: 129 self.id_valid = False 130 if self.error_msg.get('valid', None): 131 self.error = self.error_msg['valid'] 132 else: 133 self.error = "%s is invalid" % name 134 break 135 else: 136 if self.error_msg.get('valid', None): 137 self.error = self.error_msg['valid'] 138 else: 139 self.error = "%s is invalid" % name 140 141 def save(self, request, upload_path=""): 142 143 file_metas = request.files[self.name] 144 for meta in file_metas: 145 file_name = meta['filename'] 146 with open(file_name,'wb') as up: 147 up.write(meta['body']) 148 149 150 class Form(object): 151 152 def __init__(self): 153 self.value_dict = {} 154 self.error_dict = {} 155 self.valid_status = True 156 157 def validate(self, request, depth=10, pre_key=""): 158 159 self.initialize() 160 self.__valid(self, request, depth, pre_key) 161 162 def initialize(self): 163 pass 164 165 def __valid(self, form_obj, request, depth, pre_key): 166 """ 167 验证用户表单请求的数据 168 :param form_obj: Form对象(Form派生类的对象) 169 :param request: Http请求上下文(用于从请求中获取用户提交的值) 170 :param depth: 对Form内容的深度的支持 171 :param pre_key: Html中name属性值的前缀(多层Form时,内部递归时设置,无需理会) 172 :return: 是否验证通过,True:验证成功;False:验证失败 173 """ 174 175 depth -= 1 176 if depth < 0: 177 return None 178 form_field_dict = form_obj.__dict__ 179 for key, field_obj in form_field_dict.items(): 180 print key,field_obj 181 if isinstance(field_obj, Form) or isinstance(field_obj, Field): 182 if isinstance(field_obj, Form): 183 # 获取以key开头的所有的值,以参数的形式传至 184 self.__valid(field_obj, request, depth, key) 185 continue 186 if pre_key: 187 key = "%s.%s" % (pre_key, key) 188 189 if isinstance(field_obj, CheckBoxField): 190 post_value = request.get_arguments(key, None) 191 elif isinstance(field_obj, FileField): 192 post_value = [] 193 file_list = request.request.files.get(key, None) 194 for file_item in file_list: 195 post_value.append(file_item['filename']) 196 else: 197 post_value = request.get_argument(key, None) 198 199 print post_value 200 # 让提交的数据 和 定义的正则表达式进行匹配 201 field_obj.match(key, post_value) 202 if field_obj.id_valid: 203 self.value_dict[key] = field_obj.value 204 else: 205 self.error_dict[key] = field_obj.error 206 self.valid_status = False 207 208 209 class ListForm(object): 210 def __init__(self, form_type): 211 self.form_type = form_type 212 self.valid_status = True 213 self.value_dict = {} 214 self.error_dict = {} 215 216 def validate(self, request): 217 name_list = request.request.arguments.keys() + request.request.files.keys() 218 index = 0 219 flag = False 220 while True: 221 pre_key = "[%d]" % index 222 for name in name_list: 223 if name.startswith(pre_key): 224 flag = True 225 break 226 if flag: 227 form_obj = self.form_type() 228 form_obj.validate(request, depth=10, pre_key="[%d]" % index) 229 if form_obj.valid_status: 230 self.value_dict[index] = form_obj.value_dict 231 else: 232 self.error_dict[index] = form_obj.error_dict 233 self.valid_status = False 234 else: 235 break 236 237 index += 1 238 flag = False 239 240 241 class MainForm(Form): 242 243 def __init__(self): 244 # self.ip = IPField(required=True) 245 # self.port = IntegerField(required=True) 246 # self.new_ip = IPField(required=True) 247 # self.second = SecondForm() 248 self.fff = FileField(required=True) 249 super(MainForm, self).__init__() 250 251 # 252 # class SecondForm(Form): 253 # 254 # def __init__(self): 255 # self.ip = IPField(required=True) 256 # self.new_ip = IPField(required=True) 257 # 258 # super(SecondForm, self).__init__() 259 260 261 class MainHandler(tornado.web.RequestHandler): 262 def get(self): 263 self.render('index.html') 264 def post(self, *args, **kwargs): 265 # for i in dir(self.request): 266 # print i 267 # print self.request.arguments 268 # print self.request.files 269 # print self.request.query 270 # name_list = self.request.arguments.keys() + self.request.files.keys() 271 # print name_list 272 273 # list_form = ListForm(MainForm) 274 # list_form.validate(self) 275 # 276 # print list_form.valid_status 277 # print list_form.value_dict 278 # print list_form.error_dict 279 280 # obj = MainForm() 281 # obj.validate(self) 282 # 283 # print "验证结果:", obj.valid_status 284 # print "符合验证结果:", obj.value_dict 285 # print "错误信息:" 286 # for key, item in obj.error_dict.items(): 287 # print key,item 288 # print self.get_arguments('favor'),type(self.get_arguments('favor')) 289 # print self.get_argument('favor'),type(self.get_argument('favor')) 290 # print type(self.get_argument('fff')),self.get_argument('fff') 291 # print self.request.files 292 # obj = MainForm() 293 # obj.validate(self) 294 # print obj.valid_status 295 # print obj.value_dict 296 # print obj.error_dict 297 # print self.request,type(self.request) 298 # obj.fff.save(self.request) 299 # from tornado.httputil import HTTPServerRequest 300 # name_list = self.request.arguments.keys() + self.request.files.keys() 301 # print name_list 302 # print self.request.files,type(self.request.files) 303 # print len(self.request.files.get('fff')) 304 305 # obj = MainForm() 306 # obj.validate(self) 307 # print obj.valid_status 308 # print obj.value_dict 309 # print obj.error_dict 310 # obj.fff.save(self.request) 311 self.write('ok') 312 313 314 315 settings = { 316 'template_path': 'template', 317 'static_path': 'static', 318 'static_url_prefix': '/static/', 319 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 320 'login_url': '/login' 321 } 322 323 application = tornado.web.Application([ 324 (r"/index", MainHandler), 325 ], **settings) 326 327 328 if __name__ == "__main__": 329 application.listen(8888) 330 tornado.ioloop.IOLoop.instance().start()