Tornado Web 开发 框架搭建 (1)

环境配置

使 用 python 3.3 和tornado, 其实也是个人兴趣问题,然后数据库也使用mysql, 这里 使用oracle 自家的 mysql-connector. 自然,orm就选择 sqlalchemy了. 模板引擎使用jinja2, form验证考虑wtforms。

    Tornado Web 开发 框架搭建 (1)

    项目配置大概如上。之后可能使用全文检索和数据库逐步更新功能,因此又附加了 alembic 和 whoosh 俩个包。

入口

先看下 入口 server.py


?

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
#coding=utf-8
 
import tornado.ioloop
from tornado.options import define, options
from lib.base import MainApplication
from lib.routes import make_handlers, include
from settings import URL_PREFIX
# Options
#define("port", default=8888, help="run on the given port", type=int)
#define("db_path", default='sqlite:////tmp/test.db', type=str)
 
settings = {
     "template_path" : "template" ,
     "static_path" : "static" ,
     "debug" : True ,
     #"logging": "debug",
     "login_url" : '/login' ,
     "cookie_secret" : "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=" ,
     "xsrf_cookies" : True ,
}
 
#application = MainApplication([#tornado.web.Application([
#    (r"/", MainHandler),
#],**settings)
application = MainApplication(make_handlers(URL_PREFIX,
                                             (r '/' , include( 'handlers.index' )),
                                             (r '/' , include( 'handlers.user' )),
                                             (r '/' , include( 'handlers.userGroup' )),
), * * settings)
 
if __name__ = = "__main__" :
     application.listen( 8888 )
     tornado.options.options.logging = "debug"
     tornado.options.parse_command_line()
     tornado.ioloop.IOLoop.instance().start()

ROUTE

为了给tornado 实现 每个handler 单独配置url, 

类似这样  

?

1
2
3
4
5
@route ( 'login/' , name = 'login' )
class LoginHandler(BaseHandler):
     @tornado .web.asynchronous
     def get( self ):
         self .render( "login.html" )

这里自己建了一个routes.py 参考 https://github.com/troolee/tornado-routes


?

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#coding=utf-8
from pprint import pformat
import re
import logging
 
from tornado import web
from tornado.web import URLSpec
 
 
logger = logging.getLogger(__name__)
 
__ALL__ = ( 'make_handlers' , 'include' , 'route' , 'routes' , )
 
 
def handler_repr( cls ):
     return re.search( "'(.+)'" , repr ( cls )).groups()[ 0 ]
 
 
class HandlersList( object ):
     def __init__( self , prefix, items):
         self .prefix = prefix
         self .items = items
 
     def get_handler_name( self , handler, r):
         name = getattr (handler, 'url_name' , None )
         if name:
             return name
         if hasattr (handler, 'get_url_name' ):
             name = handler.get_url_name( * r)
         if name:
             return name
         if len (r) = = 3 and 'url_name' in r[ 2 ]:
             name = r[ 2 ].pop( 'url_name' )
         if name:
             return name
         return handler_repr(handler)
 
     def build( self , prefix = None ):
         prefix = prefix or self .prefix or ''
 
         res = []
         for r in self .items:
             print (r)
             route = '/' + '/' .join([prefix.strip( '/' )] + r[ 0 ].strip( '/' ).split( '/' )).strip( '/' )
             print (route)
             if isinstance (r[ 1 ], HandlersList):
                 res + = r[ 1 ].build(route)
             elif isinstance (r[ 1 ], str ):
                 m = r[ 1 ].split( '.' )
                 ms, m, h = '.' .join(m[: - 1 ]), m[ - 2 ], m[ - 1 ]
                 m = __import__ (ms, fromlist = [m], level = 0 )
                 handler = getattr (m, h)[ 0 ]
                 d = { 'name' : self .get_handler_name(handler, r)}
                 #d.update(r[2:])
                 d[ 'kwargs' ] = {}
                 if len (r) = = 3 :
                     d[ 'kwargs' ] = r[ 2 ]
                 res.append(URLSpec(route, handler, * * d))
                 if len (route) > 1 :
                     #d['kwargs']['url'] = route;
                     d.pop( 'name' )
                     res.append(URLSpec(route + '/' , handler, * * d))
             else :
                 handler = r[ 1 :][ 0 ]
                 d = { 'name' : self .get_handler_name(handler, r)}
                 d[ 'kwargs' ] = {}
                 if len (r) = = 3 :
                     d[ 'kwargs' ] = r[ 2 ]
                 res.append(URLSpec(route, handler, * * d))
                 if len (route) > 1 :
                     #d['kwargs']['url'] = route;
                     d.pop( 'name' )
                     res.append(URLSpec(route + '/' , handler, * * d))
 
         return res
 
 
def make_handlers(prefix, * args):
     res = tuple (HandlersList(prefix, args).build())
     rr = [(x.regex.pattern, x.handler_class, x.kwargs, x.name) for x in res]
     logger.debug( '\n' + pformat( sorted (rr, key = lambda a: a[ 0 ]), width = 200 ))
 
     return res
 
 
def include(module):
     def load_module(m):
         m = m.split( '.' )
         ms, m = '.' .join(m), m[ - 1 ]
         m = __import__ (ms, fromlist = [m], level = 0 )
         return m
 
     if isinstance (module, ( str ,)):
         module = load_module(module)
 
     routes = []
     for member in dir (module):
         member = getattr (module, member)
         if isinstance (member, type ) and issubclass (member, web.RequestHandler) and hasattr (member, 'routes' ):
             i = 1
             for route_path, route_params in member.routes:
                 route_path.strip( '/' )
                 if not route_params:
                     route_params = {}
                 if 'url_name' not in route_params:
                     route_params[ 'url_name' ] = '%s~%d' % (handler_repr(member), i)
                 routes.append((route_path, member, route_params))
                 i + = 1
         elif isinstance (member, type ) and issubclass (member, web.RequestHandler) and hasattr (member, 'route_path' ):
             route_path, route_params = member.route_path, member.route_params
 
             route_path.strip( '/' )
             if route_params:
                 routes.append((route_path, member, route_params))
             else :
                 routes.append((route_path, member))
         elif isinstance (member, type ) and issubclass (member, web.RequestHandler) and hasattr (member, 'rest_route_path' ):
             route_path, route_params = member.rest_route_path, member.route_params
 
             route_path.strip( '/' )
             if route_params:
                 routes.append((route_path, member, route_params))
                 routes.append((route_path + r '/([0-9]+)' , member, route_params))
             else :
                 routes.append((route_path, member))
                 routes.append((route_path + r '/([0-9]+)' , member))
     return HandlersList( None , routes)
 
 
route_classes = {}
 
 
def route(path, params = None , name = None ):
     params = params or {}
 
     def decorator( cls ):
         if repr ( cls ) in route_classes:
             raise Exception( 'Cannot bind route "%s" to %s. It already has route to "%s".' %
                             (path, cls , route_classes[ repr ( cls )]))
         route_classes[ repr ( cls )] = path
         cls .route_path = path
         cls .route_params = params
         url_name = params.pop( 'url_name' , name)
         cls .url_name = url_name
         return cls
 
     return decorator
 
 
def routes( * routes):
     def decorator( cls ):
         cls .routes = routes
         return cls
 
     return decorator

同时支持url后缀带斜杠和不带斜杠的处理

配置好的route 还可以这样用

<a href="{{ reverse_url('login') }}">Login</a>


你可能感兴趣的:(Tornado Web 开发 框架搭建 (1))