环境配置
使 用 python 3.3 和tornado, 其实也是个人兴趣问题,然后数据库也使用mysql, 这里 使用oracle 自家的 mysql-connector. 自然,orm就选择 sqlalchemy了. 模板引擎使用jinja2, form验证考虑wtforms。
项目配置大概如上。之后可能使用全文检索和数据库逐步更新功能,因此又附加了 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
|
class
LoginHandler(BaseHandler):
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>