由于tornado自带自己的模板,要把jinja2引入tornado需要做一些特殊处理
在这里,新建jinja.py 参考https://github.com/mxyzm/snail/blob/master/joiners/jinja.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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
#coding=utf-8
"""Make Jinja2 work with Tornado."""
from
tornado
import
escape
from
jinja2
import
Environment, FileSystemLoader
class
JinjaApplicationMixin(
object
):
def
__init__(
self
,
*
args,
*
*
settings):
super
(JinjaApplicationMixin,
self
).__init__(
*
args,
*
*
settings)
if
"template_path"
not
in
settings:
return
if
"template_loader"
in
settings:
loader
=
settings[
'template_loader'
]
else
:
loader
=
FileSystemLoader(settings[
'template_path'
])
if
"debug"
in
settings:
auto_reload
=
settings[
"debug"
]
else
:
auto_reload
=
False
autoescape
=
bool
(settings.get(
'autoescape'
,
False
))
self
.jinja_env
=
Environment(
loader
=
loader,
auto_reload
=
auto_reload,
autoescape
=
autoescape, )
class
JinjaHandlerMixin(
object
):
def
render_string(
self
, template_name,
*
*
context):
self
.require_setting(
"template_path"
,
"render"
)
default_context
=
{
'handler'
:
self
,
'request'
:
self
.request,
'current_user'
:
self
.current_user,
'static_url'
:
self
.static_url,
'xsrf_form_html'
:
self
.xsrf_form_html,
'reverse_url'
:
self
.reverse_url,
'me'
:
self
.oUser,
}
escape_context
=
{
'escape'
: escape.xhtml_escape,
'xhtml_escape'
: escape.xhtml_escape,
'url_escape'
: escape.url_escape,
'json_encode'
: escape.json_encode,
'squeeze'
: escape.squeeze,
'linkify'
: escape.linkify,
}
context.update(default_context)
context.update(escape_context)
context.update(
self
.ui)
# Enabled tornado UI modules and methods.
template
=
self
.application.jinja_env.get_template(
template_name)
return
template.render(
*
*
context)
|
这里我加了个当前用户对象me 给前台使用
然后主Application使用Mixin 继承 JinjaApplicationMixin
?
1
2
|
class
MainApplication(JinjaApplicationMixin, tornado.web.Application):
pass
|
server.py 里面就可以这样跑
?
1
2
3
4
|
application
=
MainApplication(make_handlers(URL_PREFIX,
(r
'/'
, include(
'handlers.index'
)),
(r
'/'
, include(
'handlers.user'
)),
(r
'/'
, include(
'handlers.userGroup'
)),
|
BaseHandler 同Mixin JinjaHandlerMixin
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class
BaseHandler(JinjaHandlerMixin, tornado.web.RequestHandler):
def
get_current_user(
self
):
user
=
self
.get_secure_cookie(
"user"
)
if
user
is
not
None
:
self
.oUser
=
self
.session.query(User).filter_by(name
=
user).first()
return
user
def
initialize(
self
):
self
.session
=
db_session
self
.oUser
=
None
def
on_finish(
self
):
self
.session.close()
|
这里已经为Sqlalchemy的session处理和 tornado的用户登录验证打好基础,等以后再做说明。
然后在handler里面使用:
?
1
2
3
4
5
6
|
@route
('
', name='
index')
class
IndexHandler(BaseHandler):
@tornado
.web.authenticated
@tornado
.web.asynchronous
def
get(
self
):
self
.render(
"index.html"
)
|
注意:
JinjaHandlerMixin里面的context是可以自己修改和添加的
在做BaseHandler的多继承的时候,一定要把mixin的放在前面,RequestHandler放后面
在server.py里面做下template_path 的配置
然后,在主页面里面就可以按jinja2的方式写模板了。理论上说,tornado的UI模块也能一起使用,但是个人觉得jinja2 的macro 也同样能实现相应功能,这里就没做测试。
下面是登录窗口的示例
?
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
|
{
%
extends
"base.html"
%
}
{
%
block title
%
}登陆{
%
endblock
%
}
{
%
block css
%
}
<style
type
=
"text/css"
>
body {
padding
-
top:
40px
;
padding
-
bottom:
40px
;
background
-
color:
#eee;
}
.form
-
signin {
max
-
width:
330px
;
padding:
15px
;
margin:
0
auto;
}
.form
-
signin .form
-
signin
-
heading,
.form
-
signin .checkbox {
margin
-
bottom:
10px
;
}
.form
-
signin .checkbox {
font
-
weight: normal;
}
.form
-
signin .form
-
control {
position: relative;
font
-
size:
16px
;
height: auto;
padding:
10px
;
-
webkit
-
box
-
sizing: border
-
box;
-
moz
-
box
-
sizing: border
-
box;
box
-
sizing: border
-
box;
}
.form
-
signin .form
-
control:focus {
z
-
index:
2
;
}
.form
-
signin
input
[
type
=
"text"
] {
margin
-
bottom:
-
1px
;
border
-
bottom
-
left
-
radius:
0
;
border
-
bottom
-
right
-
radius:
0
;
}
.form
-
signin
input
[
type
=
"password"
] {
margin
-
bottom:
10px
;
border
-
top
-
left
-
radius:
0
;
border
-
top
-
right
-
radius:
0
;
}
<
/
style>
{
%
endblock
%
}
{
%
block body
%
}
<div
class
=
"container"
>
<form
class
=
"form-signin"
method
=
"post"
>
{{ xsrf_form_html() }}
<h2
class
=
"form-signin-heading"
>登录<
/
h2>
<
input
name
=
"name"
type
=
"text"
class
=
"form-control"
placeholder
=
"用户名"
autofocus>
<
input
name
=
"pwd"
type
=
"password"
class
=
"form-control"
placeholder
=
"密码"
>
{
%
if
form|d(none)
is
not
none
%
}
<div
class
=
"alert alert-danger"
>
{{ form.mainerr}}
<
/
div>
{
%
endif
%
}
<label
class
=
"checkbox"
>
<
input
name
=
"remember"
type
=
"checkbox"
value
=
"remember"
>记住我
<
/
label>
<button
class
=
"btn btn-lg btn-primary btn-block"
type
=
"submit"
>登录<
/
button>
<
/
form>
<
/
div> <!
-
-
/
container
-
-
>
{
%
endblock
%
}
|
静态文件通常如下使用:
?
1
|
<link href
=
"{{ static_url("
css
/
bootstrap.
min
.css
") }}"
rel
=
"stylesheet"
media
=
"screen"
>
|
需要在 server.py里面配置下 static_path