tornado框架之模型绑定

发布时间 2023-12-08 15:17:42作者: 木屐呀

模型绑定有两个主要功能:

  • 自动生成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>
index.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()
tornado_test.py

由于请求验证时,需要考虑是否可以为空以及正则表达式的复用,所以:

  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()
Form验证框架