Tornado之模板
知识点
- 静态文件配置
- static_path
- StaticFileHandler
- 模板使用
- 变量与表达式
- 控制语句
- 函数
- 块
4.1 静态文件
现在有一个预先写好的静态页面文件 (下载静态文件资源), 我们来看下如何用tornado提供静态文件。
static_path
我们可以通过向web.Application类的构造函数传递一个名为static_path的参数来告诉Tornado从文件系统的一个特定位置提供静态文件,如:
app = tornado.web.Application([(r'/', IndexHandler)],static_path=os.path.join(os.path.dirname(__file__), "statics"), )
在这里,我们设置了一个当前应用目录下名为statics的子目录作为static_path的参数。现在应用将以读取statics目录下的filename.ext来响应诸如/static/filename.ext的请求,并在响应的主体中返回。
对于静态文件目录的命名,为了便于部署,建议使用static
对于我们提供的静态文件资源,可以通过http://127.0.0.1/static/html/index.html
来访问。而且在index.html中引用的静态资源文件,我们给定的路径也符合/static/...的格式,故页面可以正常浏览。
<link href="/static/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet"> <link href="/static/css/reset.css" rel="stylesheet"> <link href="/static/css/main.css" rel="stylesheet"> <link href="/static/css/index.css" rel="stylesheet"> <script src="/static/js/jquery.min.js"></script> <script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script> <script src="/static/js/index.js"></script>
StaticFileHandler
我们再看刚刚访问页面时使用的路径http://127.0.0.1/static/html/index.html
,这中url显然对用户是不友好的,访问很不方便。我们可以通过tornado.web.StaticFileHandler来自由映射静态文件与其访问路径url。
tornado.web.StaticFileHandler是tornado预置的用来提供静态资源文件的handler。
import oscurrent_path = os.path.dirname(__file__) app = tornado.web.Application([(r'^/()$', StaticFileHandler, {"path":os.path.join(current_path, "statics/html"), "default_filename":"index.html"}),(r'^/view/(.*)$', StaticFileHandler, {"path":os.path.join(current_path, "statics/html")}),],static_path=os.path.join(current_path, "statics"), )
- path 用来指明提供静态文件的根路径,并在此目录中寻找在路由中用正则表达式提取的文件名。
- default_filename 用来指定访问路由中未指明文件名时,默认提供的文件。
现在,对于静态文件statics/html/index.html,可以通过三种方式进行访问:
- http://127.0.0.1/static/html/index.html
- http://127.0.0.1/
- http://127.0.0.1/view/index.html
4.2 使用模板
1. 路径与渲染
使用模板,需要仿照静态文件路径设置一样,向web.Application类的构造函数传递一个名为template_path的参数来告诉Tornado从文件系统的一个特定位置提供模板文件,如:
app = tornado.web.Application([(r'/', IndexHandler)],static_path=os.path.join(os.path.dirname(__file__), "statics"),template_path=os.path.join(os.path.dirname(__file__), "templates"), )
在这里,我们设置了一个当前应用目录下名为templates的子目录作为template_path的参数。在handler中使用的模板将在此目录中寻找。
现在我们将静态文件目录statics/html中的index.html复制一份到templates目录中,此时文件目录结构为:
. ├── statics │ ├── css │ │ ├── index.css │ │ ├── main.css │ │ └── reset.css │ ├── html │ │ └── index.html │ ├── images │ │ ├── home01.jpg │ │ ├── home02.jpg │ │ ├── home03.jpg │ │ └── landlord01.jpg │ ├── js │ │ ├── index.js │ │ └── jquery.min.js │ └── plugins │ ├── bootstrap │ │ └─... │ └── font-awesome │ └─... ├── templates │ └── index.html └── test.py
在handler中使用render()方法来渲染模板并返回给客户端。
class IndexHandler(RequestHandler):def get(self):self.render("index.html") # 渲染主页模板,并返回给客户端。current_path = os.path.dirname(__file__) app = tornado.web.Application([(r'^/$', IndexHandler),(r'^/view/(.*)$', StaticFileHandler, {"path":os.path.join(current_path, "statics/html")}),],static_path=os.path.join(current_path, "statics"),template_path=os.path.join(os.path.dirname(__file__), "templates"), )
2. 模板语法
2-1 变量与表达式
在tornado的模板中使用{{}}作为变量或表达式的占位符,使用render渲染后占位符{{}}会被替换为相应的结果值。
我们将index.html中的一条房源信息记录
<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>398</span>/晚</div><div class="house-intro"><span class="house-title">宽窄巷子+160平大空间+文化保护区双地铁</span><em>整套出租 - 5分/6点评 - 北京市丰台区六里桥地铁</em></div></div> </li>
改为模板:
<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>{{price}}</span>/晚</div><div class="house-intro"><span class="house-title">{{title}}</span><em>整套出租 - {{score}}分/{{comments}}点评 - {{position}}</em></div></div> </li>
渲染方式如下:
class IndexHandler(RequestHandler):def get(self):house_info = {"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"}self.render("index.html", **house_info)
{{}}不仅可以包含变量,还可以是表达式,如:
<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>{{p1 + p2}}</span>/晚</div><div class="house-intro"><span class="house-title">{{"+".join(titles)}}</span><em>整套出租 - {{score}}分/{{comments}}点评 - {{position}}</em></div></div> </li> class IndexHandler(RequestHandler):def get(self):house_info = {"p1": 198,"p2": 200,"titles": ["宽窄巷子", "160平大空间", "文化保护区双地铁"],"score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"}self.render("index.html", **house_info)
2-2 控制语句
可以在Tornado模板中使用Python条件和循环语句。控制语句以{\%和\%}包围,并以类似下面的形式被使用:
{% if page is None %}
或
{% if len(entries) == 3 %}
控制语句的大部分就像对应的Python语句一样工作,支持if、for、while,注意end:
{% if ... %} ... {% elif ... %} ... {% else ... %} ... {% end %} {% for ... in ... %} ... {% end %} {% while ... %} ... {% end %}
再次修改index.html:
<ul class="house-list">{% if len(houses) > 0 %}{% for house in houses %}<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>{{house["price"]}}</span>/晚</div><div class="house-intro"><span class="house-title">{{house["title"]}}</span><em>整套出租 - {{house["score"]}}分/{{house["comments"]}}点评 - {{house["position"]}}</em></div></div></li>{% end %}{% else %}对不起,暂时没有房源。{% end %} </ul>
python中渲染语句为:
class IndexHandler(RequestHandler):def get(self):houses = [{"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"},{"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"},{"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"},{"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"},{"price": 398,"title": "宽窄巷子+160平大空间+文化保护区双地铁","score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"}]self.render("index.html", houses=houses)
2-3 函数
static_url()
Tornado模板模块提供了一个叫作static_url的函数来生成静态文件目录下文件的URL。如下面的示例代码:
<link rel="stylesheet" href="{{ static_url("style.css") }}">
这个对static_url的调用生成了URL的值,并渲染输出类似下面的代码:
<link rel="stylesheet" href="/static/style.css?v=ab12">
优点:
- static_url函数创建了一个基于文件内容的hash值,并将其添加到URL末尾(查询字符串的参数v)。这个hash值确保浏览器总是加载一个文件的最新版而不是之前的缓存版本。无论是在你应用的开发阶段,还是在部署到生产环境使用时,都非常有用,因为你的用户不必再为了看到你的静态内容而清除浏览器缓存了。
- 另一个好处是你可以改变你应用URL的结构,而不需要改变模板中的代码。例如,可以通过设置static_url_prefix来更改Tornado的默认静态路径前缀/static。如果使用static_url而不是硬编码的话,代码不需要改变。
转义
我们新建一个表单页面new.html
<!DOCTYPE html> <html><head><title>新建房源</title></head><body><form method="post"><textarea name="text"></textarea><input type="submit" value="提交"></form>{{text}}</body> </html>
对应的handler为:
class NewHandler(RequestHandler):def get(self):self.render("new.html", text="")def post(self):text = self.get_argument("text", "") print textself.render("new.html", text=text)
当我们在表单中填入如下内容时:
<script>alert("hello!");</script>
写入的js程序并没有运行,而是显示出来了:
我们查看页面源代码,发现<、>、"等被转换为对应的html字符。
<script>alert("hello!");</script>
这是因为tornado中默认开启了模板自动转义功能,防止网站受到恶意攻击。
我们可以通过raw语句来输出不被转义的原始格式,如:
{% raw text %}
注意:在Firefox浏览器中会直接弹出alert窗口,而在Chrome浏览器中,需要set_header("X-XSS-Protection", 0)
若要关闭自动转义,一种方法是在Application构造函数中传递autoescape=None,另一种方法是在每页模板中修改自动转义行为,添加如下语句:
{% autoescape None %}
escape()
关闭自动转义后,可以使用escape()函数来对特定变量进行转义,如:
{{ escape(text) }}
自定义函数
在模板中还可以使用一个自己编写的函数,只需要将函数名作为模板的参数传递即可,就像其他变量一样。
我们修改后端如下:
def house_title_join(titles):return "+".join(titles)class IndexHandler(RequestHandler):def get(self):house_list = [{"price": 398,"titles": ["宽窄巷子", "160平大空间", "文化保护区双地铁"],"score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"},{"price": 398,"titles": ["宽窄巷子", "160平大空间", "文化保护区双地铁"],"score": 5,"comments": 6,"position": "北京市丰台区六里桥地铁"}]self.render("index.html", houses=house_list, title_join = house_title_join)
前段模板我们修改为:
<ul class="house-list">{% if len(houses) > 0 %}{% for house in houses %}<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>{{house["price"]}}</span>/晚</div><div class="house-intro"><span class="house-title">{{title_join(house["titles"])}}</span><em>整套出租 - {{house["score"]}}分/{{house["comments"]}}点评 - {{house["position"]}}</em></div></div></li>{% end %}{% else %}对不起,暂时没有房源。{% end %} </ul>
2-4 块
我们可以使用块来复用模板,块语法如下:
{% block block_name %} {% end %}
现在,我们对模板index.html进行抽象,抽离出父模板base.html如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">{% block page_title %}{% end %}<link href="{{static_url('plugins/bootstrap/css/bootstrap.min.css')}}" rel="stylesheet"><link href="{{static_url('plugins/font-awesome/css/font-awesome.min.css')}}" rel="stylesheet"><link href="{{static_url('css/reset.css')}}" rel="stylesheet"><link href="{{static_url('css/main.css')}}" rel="stylesheet">{% block css_files %}{% end %} </head> <body><div class="container"><div class="top-bar">{% block header %}{% end %}</div>{% block body %}{% end %}<div class="footer">{% block footer %}{% end %}</div></div><script src="{{static_url('js/jquery.min.js')}}"></script><script src="{{static_url('plugins/bootstrap/js/bootstrap.min.js')}}"></script>{% block js_files %}{% end %} </body> </html>
而子模板index.html使用extends来使用父模板base.html,如下:
{% extends "base.html" %}{% block page_title %}<title>爱家-房源</title> {% end %}{% block css_files %}<link href="{{static_url('css/index.css')}}" rel="stylesheet"> {% end %} {% block js_files %}<script src="{{static_url('js/index.js')}}"></script> {% end %}{% block header %}<div class="nav-bar"><h3 class="page-title">房 源</h3></div> {% end %}{% block body %}<ul class="house-list">{% if len(houses) > 0 %}{% for house in houses %}<li class="house-item"><a href=""><img src="/static/images/home01.jpg"></a><div class="house-desc"><div class="landlord-pic"><img src="/static/images/landlord01.jpg"></div><div class="house-price">¥<span>{{house["price"]}}</span>/晚</div><div class="house-intro"><span class="house-title">{{title_join(house["titles"])}}</span><em>整套出租 - {{house["score"]}}分/{{house["comments"]}}点评 - {{house["position"]}}</em></div></div></li>{% end %}{% else %}对不起,暂时没有房源。{% end %}</ul> {% end %}{% block footer %}<p><span><i class="fa fa-copyright"></i></span>爱家租房 享受家的温馨</p> {% end %}
4.3 练习
对比Django模板与Tornado模板的异同。
练习使用Tornado模板的语法。
4.3 练习
对比Django模板与Tornado模板的异同。
练习使用Tornado模板的语法。
转载于:https://www.cnblogs.com/alexzhang92/p/9379928.html
Tornado之模板相关推荐
- 11 Tornado - 使用模板
1. 路径与渲染 使用模板,需要仿照静态文件路径设置一样,向web.Application类的构造函数传递一个名为template_path的参数来告诉Tornado从文件系统的一个特定位置提供模板文 ...
- web框架详解之 tornado 四 模板引擎、session、验证码、xss
一.模板引擎 基本使用继承,extends 页面整体布局用继承导入,include 如果是小组件等重复的那么就用导入 下面是目录 首先在controllers里面创建一个文件,文件里面是页面类 #/u ...
- Python3 --- Tornado之模板
目录 一.模板渲染 二.模板语法 2.1.变量输出 2.2.表达式输出 2.3.注释一个部分,防止他被输出 2.4.模板替换 2.5.模板继承 2.6.for循环 2.7.from引入包 2.8.im ...
- t4 tornado 模板
4.1 静态文件 现在有一个预先写好的静态页面文件 (下载静态文件资源), 我们来看下如何用tornado提供静态文件. static_path 我们可以通过向web.Application类的构造函 ...
- Python学习笔记——Tornado模板
4.1 静态文件 现在有一个预先写好的静态页面文件 (下载静态文件资源), 我们来看下如何用tornado提供静态文件. static_path 我们可以通过向web.Application类的构造函 ...
- 3.(基础)tornado的接口调用顺序与模板
上一节介绍了tornado的请求与响应,这一节介绍tornado的接口调用顺序和模板 首先都有哪些接口呢?作用是什么呢?并且都有的时候,执行顺序是怎么样的呢? 接口 1.initialize,表示初始 ...
- 模板数据tornado开发学习之2.输入输出,数据库操作,内置模板,综合示例
最近用应开辟的过程中现出了一个小题问,趁便记载一下原因和方法--模板数据 用应python境环中的tornado行进web开辟上篇已决解了urlmap和基本行运机制的题问.接下来行进web程编就是一下 ...
- tornado模板引擎原理
前言 老师问小明:已经a=1, 求a+1的值. 小明挠挠头,思考后回答:老师,a+1的结果是2. 以上是一个非常简单的例子,实际上就是一个模板编译过程. a=1,表示一个命名空间(namespace) ...
- tornado 入门
Overview FriendFeed是一款使用 Python 编写的,相对简单的 非阻塞式 Web 服务器.其应用程序使用的 Web 框架看起来有些像 web.py 或者 Google 的 weba ...
最新文章
- 预计2020年传感器需求超一万亿个
- git最佳实践_Git最佳实践如何为我节省大量的返工时间
- dns tunnel 使用 nishang 下载TXT里的cmd(TXT里)实现CC command+ ceye实现数据外发
- Python中列表的copy方法
- WordPress按钮秒支付插件发布,支持微信支付,支付宝,银联,京东,苏宁,易宝支付...
- 财经计算机财务函数,会计财务最常用的15个公式函数
- 洛谷 3784(bzoj 4913) [SDOI2017]遗忘的集合——多项式求ln+MTT
- 专注于元宇宙后 Meta今年将取消举办F8开发者大会
- windows2008开机占用多少内存_如何提升电脑开机速度?
- Atitit sift匹配度计算 图片连线 oepncv sift java匹配
- 剩余电流互感器互感电流放大转真有效值
- Win11退Win10/重装Win10如何查询系统密钥
- 计算机键盘优点,市面上的笔记本键盘优缺点解析,看完秒懂!
- 强制跳过WM调整屏幕的方法
- 466. 统计重复个数
- 终于有人把大数定律讲明白了
- 包装类和自动拆箱与自动装箱
- QT中将文件夹内文件名称显示到tableview,对显示的文件名双击直接打开文件
- 字符串加密与解密_一种可以用在程序加密的功能
- tshark 使用说明
热门文章
- 安卓调用系统相机进行拍照
- Android Jetpack架构组件之Navigation
- 刘晓燕核心词汇趣讲笔记-第十课
- 如何用命令关闭/启动mysql服务
- Android技术点汇总
- Identifying and Tracking Sentiments and Topics from Social
- 关于sockjs.js?9be2:1606 GET http://****/sockjs-node/info?t=1581148413474 net::ERR_CONNECTI 错误解决方案
- 深度产教融合的“山东经验”
- 【 OJ 】 HDOJ1035 迷宫类问题模拟走向 [ 32 ]
- 141.如何个性化推荐系统设计-1