工作中看到有一些不好的代码,想了个办法优化了一下,于是有了这篇博文。本文主要讲tornado的表单验证,使用的是wtforms。本文最终达到的效果是使用self.xx获取post传递过来的值。

首先是将wtforms嵌入tornado。做法可以参考https://github.com/truemped/tornadotools/blob/master/tornadotools/forms.py,我的做法类似,可以看最下面的代码。这样继承一下就能够使用wtforms的表单验证了。能够使用的结果是很多人写这样的代码

1
2
3
4
5
self.xx1 = self.form.xx1.data
self.xx2 = self.form.xx2.data
self.xx3 = self.form.xx3.data
:
:

然后这样写了20行(不黑,项目里真有这样的)。写的人也确实是很认真啊!,改进的方法很简单。调用self.xx1的时候自动取值self.form.xx1.data。能做成这样的方法挺多。很多时候会导致self.xxx使用IDE无法补全。我个人认为好的代码肯定能够方便的补全和提示,毕竟这样能实打实的提升码代码的心情,试想一下你要输入20个单词,很可能一不小心就输入错误了。改进的方法就是使用__getattribute__,配合类继承,兼顾自动补全也不用跑去写self.form.xxx.data了

  1. __getattr__,当属性不存在的时候会调用
  2. __getattribute__,无论属性是否存在都会被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import tornado.ioloop
import tornado.web

from wtforms import validators, fields
from wtforms import Form
from wtforms.fields.core import UnboundField


class MultiDict(dict):
def getlist(self, key):
return self[key]

def setlist(self, key, value):
self[key] = value


class BaseForm(Form):
def __init__(self, handler=None, obj=None, prefix='', **kwargs):
if handler is None:
return
formdata = MultiDict()
if handler.request.method == 'POST':
for name in handler.request.arguments.keys():
formdata.setlist(name, handler.get_arguments(name))
else:
for name in handler.request.query_arguments.keys():
formdata.setlist(name, handler.request.query_arguments[name])
Form.__init__(self, formdata, obj=obj, prefix=prefix, **kwargs)


class LoginForm(BaseForm):
email = fields.StringField(
validators=[validators.Email(), validators.required(), validators.length(min=5, max=64)])
password = fields.PasswordField(validators=[validators.required()])


class MainHandler(tornado.web.RequestHandler, LoginForm):
def __getattribute__(self, item):
ret = object.__getattribute__(self, item)
if isinstance(ret, UnboundField):
form = object.__getattribute__(self, 'form')
return getattr(form, item).data
return ret

def post(self):
self.form = LoginForm(self)
print(self.email)
self.write("Hello, world")


def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])


if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()

完美解决问题,心情瞬间舒畅了┑( ̄Д  ̄)┍