模板设置
由于tornado自带自己的模板,要把jinja2引入tornado需要做一些特殊处理
在这里,新建jinja.py 参考https://github.com/mxyzm/snail/blob/master/joiners/jinja.py
#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
class MainApplication(JinjaApplicationMixin, tornado.web.Application):
pass
server.py 里面就可以这样跑
application = MainApplication(make_handlers(URL_PREFIX,
(r'/', include('handlers.index')),
(r'/', include('handlers.user')),
(r'/', include('handlers.userGroup')),
BaseHandler 同Mixin JinjaHandlerMixin
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里面使用:
@route('', name='index')
class IndexHandler(BaseHandler):
@tornado.web.authenticated
@tornado.web.asynchronous
def get(self):
self.render("index.html")
注意:
- JinjaHandlerMixin里面的context是可以自己修改和添加的
- 在做BaseHandler的多继承的时候,一定要把mixin的放在前面,RequestHandler放后面
然后,在主页面里面就可以按jinja2的方式写模板了。理论上说,tornado的UI模块也能一起使用,但是个人觉得jinja2 的macro 也同样能实现相应功能,这里就没做测试。
下面是登录窗口的示例
{% 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 %}
静态文件通常如下使用:
<link href="{{ static_url("css/bootstrap.min.css") }}" rel="stylesheet" media="screen">
需要在 server.py里面配置下
static_path