共计 9879 个字符,预计需要花费 25 分钟才能阅读完成。
一、模板配置
-
概述
使用模板 需要仿照静态资源文件路径设置 向 web.Application 类的构造函数传递一个名为 template_path 的参数 来告诉 tornado 从文件系统的一个特定位置 提供模板文件
-
配置如下
BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([(r'/',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), debug=True, autoreload=True, )
我们设置了一个当前应用目录下名为 templates 的子目录作为 template_path 的参数。在 handler 中使用的模板将在此目录中寻找
-
目录结构
project/ static/ templates/ common/ index.html manage.py
二、模板渲染
-
render(“模板名称”,**kwargs)
不传递参数示例
import tornado.web import tornado.ioloop import os class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") if __name__ == '__main__': BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([(r'/',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), debug=True, autoreload=True, ) app.listen(8000) tornado.ioloop.IOLoop.current().start()
传递参数示例
概述:
函数向模板中传递的参数 也就是变量 在模板中使用 {{变量名称}} 进行获取值
处理类代码
class IndexHandler(tornado.web.RequestHandler): def get(self): userInfo = {'name':'lucky', 'age':18, 'sex':'man', 'num': 10 } # 传递参数和 flask 一样 # 一次传递多个值 self.render("index.html",userInfo = userInfo)
模板文件代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2> 首页 </h2> <h4> 获取传递的参数 </h4> <p>{{userInfo}}</p> <p>{{userInfo['name'] }}</p> <p>{{userInfo['sex'] }}</p> <p>{{userInfo['age'] }}</p> <h5> 表达式(也就是可以在变量中进行运算操作)</h5> <p>{{userInfo['age'] + userInfo['num'] }}</p> <h5> 测试如果使用的变量不存在(也就是没有传递)结果为会报错 </h5> <p>{{boy}}</p> </body> </html>
注意:
- 如果在模板中使用了未传递的变量 则报错
- 视图传递给模板的数据
- 要遵守标识符规则
- 语法:{{var}}
三、标签
-
语法: {% tag %}
-
说明
可以在 Tornado 模板中 使用 Python 条件和循环语句 标签使用 {% 标签名称 %} 来使用
-
作用
在输出中创建文本
控制逻辑和循环
-
if 标签
格式
{% if ...%} ... {% elif ... %} ... {% else %} ... {% end %}
示例
{% if grade >= 90 %} 成绩优秀 {% elif grade >= 80 %} 成绩良好 {% else %} 成绩不太理想 {% end %}
-
for 标签
格式
{% for xx in xx %} 循环体 {% end %}
示例
视图函数代码为:
class IndexHandler(tornado.web.RequestHandler): def get(self): userInfo = {'name':'lucky', 'age':18, 'sex':'man', 'num':10, } # 传递参数和 flask 一样 # 一次传递多个值 self.render("index.html",userInfo = userInfo) class TagHandler(tornado.web.RequestHandler): def get(self): userInfo = {'name': 'lucky', 'age': 18, 'sex': 'man', 'num': 10, } self.render('test_tag.html',grade=70,userInfo=userInfo)
模板代码
<ol> {% for k,v in userInfo.items() %} <li>{{k}}----{{v}}</li> {% end %} </ol>
-
转义
说明:tornado 默认开启了模板自动转义功能 防止网站收到恶意攻击
-
示例
def get(self):
self.render(“index.html”,html=“Hello Lucky”)
“`
模板渲染结果为:`<b>Hello Lucky</b>`
-
关闭转义的方式
第一种 raw 用来输出不被转义的原始格式
示例
{% raw html %}
“`
第二种 设置关闭自动转义功能
在 python 配置中
```python
app = tornado.web.Application([],
autoescape=None,
)
“`
第三种 模板中
```phthon
{% autoescape None %}
“`
-
转义变量
{{escape( 需要转义的变量) }}
“`
-
模板导入 include
-
概述
可以将指定的 HTML 文件 在模板中的某个位置进行导入使用 实现模板代码的复用 以及减轻后期代码的维护
-
格式
{% include "路径 / 模板名称.html" %}
-
示例
目录结构
project/ templates/ common/ header.html footer.html index.html manage.py
index.html 代码如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'common/header.html' %} <h2> 首页 </h2> {% include 'common/footer.html' %} </body> </html>
header.html
<header> <h4> 头部分 </h4> </header>
footer.html
<footer> <h4> 尾部分 </h4> </footer>
-
注意事项
我们在使用 include 的时候 会将到入文件内的所有代码都拿过来 所以注意被导入的文件中不要有其它代码的存在 否则都会被导入过来
-
-
模板继承
标签:
-
extends 继承
格式
{% extends '父模板.html' %}
-
block 使用块填充
格式:
{% block '名称' %} ... {% end %}
-
示例
目录结构
project/ templates/ common/ base.html index.html
base.html 代码如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %} 标题 {% end %}</title> </head> <body> {% block header %} <h2> 页面头部分 </h2> {% end %} {% block content %} <h2> 页面内容部分 </h2> {% end %} </body> </html>
index.html
{% extends 'common/base.html' %} {% block title %} 首页 {% end %} {% block header %} <h4> 首页 </h4> {% end %}
使用 bootstrap 创建 base 模板
base.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %} 标题 {% end %}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> {% block styles %} {% end %} </head> <body> {% block header %} <nav class="navbar navbar-inverse" style="border-radius: 0px;"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#"> 首页 <span class="sr-only">(current)</span></a></li> <li><a href="#"> 发表博客 </a></li> </ul> <ul class="nav navbar-nav navbar-right"> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Search</button> </form> <li><a href="#"> 登录 </a></li> <li><a href="#"> 注册 </a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> 个人中心 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#"> 个人资料 </a></li> <li><a href="#"> 头像修改 </a></li> <li><a href="#"> 我的博客 </a></li> <li role="separator" class="divider"></li> <li><a href="#"> 退出登录 </a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> {% end %} <div class="container"> {% block content %} <h1> 你好,Lucky!</h1> {% end %} </div> {% block scripts %} <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) --> <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script> <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。--> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> {% end %} </body> </html>
-
注意
在子模板中 如果想对父母版中的哪个 block 的位置进行更改 那么就使用 block 名称 进行替换 当替换以后 内容为你替换后的内容 若是没有进行替换 则内容为原内容
-
四、自定义函数
-
说明
在模板中还可以使用一个自己编写的函数 只需要将函数名作为模板的参数传递即可 就像其它变量一样
-
示例
处理类中
# 自定义函数 在模板中进行使用 def my_join(con): return '+'.join(con) class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html",my_join=my_join)
模板中
<h4> 传递函数在模板中使用 </h4> {{my_join('lucky') }}
五、静态文件
说明:我们的图片、样式、js 效果 统称为我们的静态资源文件 需要配置静态资源目录 static 进行使用
-
目录结构
project/ static/ img/ css/ js/ upload/ manage.py
-
static_path
- 说明:我们可以通过向 web.Application 类的构造函数传递一个名为 static_path 的参数来告诉 Tornado 从文件系统的一个特定位置提供静态文件
-
配置如下
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = tornado.web.Application([(r'/', IndexHandler)], static_path=os.path.join(BASE_DIR, "static"), )
static_path 配置了静态资源访问的目录
-
代码示例
import tornado.ioloop import tornado.httpserver from tornado.web import RequestHandler, Application import os class IndexHandler(RequestHandler): def get(self): self.render('index.html') if __name__ == "__main__": BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = Application([(r"/", IndexHandler), ], static_path=os.path.join(BASE_DIR, "static"), template_path=os.path.join(BASE_DIR, "templates"), debug = True, ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000) tornado.ioloop.IOLoop.current().start()
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/test.css"> <script src="/static/js/test.js"></script> </head> <body> <img src="/static/img/test.jpg" alt=""> </body> </html>
注意:对于静态文件目录的命名,为了便于部署,建议使用 static
-
模板中动态构造
格式
{{static_url('plugins/bootstrap/css/bootstrap.min.css')}}
示例
<img src="{{static_url('img/a.jpg')}}" alt="">
解析后
<img src="/static/img/test.jpg?v=11c671ed35a4611f3576ab4cbe5ee59c" alt="">
优点
- static_url 函数创建了一个基于文件内容的 hash 值 并将其添加到 URL 末尾 (查询字符串的参数 v) 这个 hash 值确保浏览器总是加载一个文件的最新版 而不是之前的缓存版本 无论是在应用到开发阶段 还是在部署环境中 都非常有用 因为用户不必在为了看到最新的页面内容而清除浏览器缓存了
- 另外一个好处可以动态改变应用 URL 的结构 而不需要改变模板中的代码 需要配置 static_url_prefix 来进行更改 如果你使用它进行了更改 那么模板中不需要改变
前缀示例
BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([(r'^/$',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), static_path=os.path.join(BASE_DIR,'static'), debug=True, static_url_prefix='/lucky/', )
-
直接通过 url 进行访问
http://127.0.0.1:8000/static/img/test.jpg
-
-
StaticFileHandler
-
说明
- 我们再看刚刚访问页面时使用的路径
http://127.0.0.1:8000/static/img/test.jpg
,这中 url 显然对用户是不友好的,访问很不方便。我们可以通过 tornado.web.StaticFileHandler 来自由映射静态资源文件与其访问的路径 url - urltornado.web.StaticFileHandler 是 tornado 预置的用来提供静态资源文件的 handler
- 我们再看刚刚访问页面时使用的路径
-
示例
import os from tornado.web import StaticFileHandler BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = Application( [(r'^/(.*?)$', StaticFileHandler, {"path":os.path.join(BASE_DIR, "static/img"), "default_filename":"test.jpg"}), (r'^/view/(.*)$', StaticFileHandler, {"path":os.path.join(BASE_DIR, "static/img")}), ], static_path=os.path.join(BASE_DIR, "static"), template_path=os.path.join(BASE_DIR, 'templates'), )
模板中
<img src="/static/img/a.jpg" alt=""> <img src="/view/a.jpg" alt=""> <img src="/" alt=""> <img src="/b.jpg" alt="">
-
参数说明
path 用来指明提供静态文件的根路径,并在此目录中寻找在路由中用正则表达式提取的文件名
default_filename 用来指定访问路由中未指明文件名时,默认提供的文件
-
现在,对于静态文件 statics/img/test.jpg,可以通过三种方式进行访问:
http://127.0.0.1:8000/static/img/test.jpg
http://127.0.0.1:8000/
http://127.0.0.1:8000/test.jpg
http://127.0.0.1:8000/view/test.jpg
六、文件上传
文件上传注意事项
- 表单的 enctype 注意修改在进行文件上传的时候
- 文件上传的文本域 需要存在 name 属性值
- 提交方式为 post
示例
import tornado.web
import tornado.ioloop
import os
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
# 处理文件上传内的 Handler
class UploadHandler(tornado.web.RequestHandler):
def get(self):
self.render('upload.html')
def post(self):
# 获取上传过来的文件
files = self.request.files
if files:
# 取出包含当前上传文件数据的列表
img = files.get('img')
# 获取上传文件名称 (获取到文件名称 是不是可以自己通过文件名称判断该类型文件是否允许上传 以及生成新的文件唯一名称)
filename = img[0]['filename']
img_file = img[0]['body']
# 文件的存储操作
# 拼接文件上传存储路径
path = os.path.join('static/upload',filename)
file = open(path,'wb')
file.write(img_file)
file.close()
# 上传成功还可以对文件进行大小缩放 以适应其他场合的使用
self.write('文件上传成功')
self.write('来了老弟')
if __name__ == '__main__':
app = tornado.web.Application([(r'/',IndexHandler),
(r'/upload/',UploadHandler),
],
debug=True,
autoreload=True,
template_path=os.path.join(os.path.dirname(__file__),'templates'),
)
app.listen(8000)
tornado.ioloop.IOLoop.current().start()
upload.html
{% extends 'common/base.html' %}
{% block title %}
文件上传
{% end %}
{% block content %}
<div class="page-header"><h2> 文件上传 </h2></div>
<form action="/upload/" method="post" enctype="multipart/form-data">
<p><input type="file" name="img"></p>
<p><input type="submit" value="上传"></p>
</form>
{% end %}