pythonWeb框架 Tornado
一、快速开始
1,helloWorld
1, 创建一个处理类继承自 tornado.web.RequestHandler
2,处理类重写get方法
3,编写主函数监听端口
#-*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop
#定义处理类型
class IndexHandler(tornado.web.RequestHandler):
#添加一个处理get请求方式的方法
def get(self):
#向响应中,添加数据
self.write('好看的皮囊千篇一律,有趣的灵魂万里挑一。')
if __name__ == '__main__':
#创建一个应用对象
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
#绑定一个监听端口
app.listen(8888)
#启动web程序,开始监听端口的连接
tornado.ioloop.IOLoop.current().start()
handels 属性作用(映射配置)
这里的参数handlers非常重要,值得我们更加深入的研究。它应该是一个元组组成的列表,其中每个元组的第一个元素是一个用于匹配的正则表达式,第二个元素是一个RequestHanlder类。在hello.py中,我们只指定了一个正则表达式-RequestHanlder对,但你可以按你的需要指定任意多个。
创建APP时可以通过设置 debug=True 开启热部署
2, 带参数的get/Post方法
#-*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop
#定义处理类型
class IndexHandler(tornado.web.RequestHandler):
#添加一个处理get请求方式的方法
def get(self):
#向响应中,添加数据
self.write('好看的皮囊千篇一律,有趣的灵魂万里挑一。')
noun1 = self.get_argument('noun1')
if __name__ == '__main__':
#创建一个应用对象
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
#绑定一个监听端口
app.listen(8888)
#启动web程序,开始监听端口的连接
tornado.ioloop.IOLoop.current().start()
self.get_argument()函数获取请求参数,Post同理。
3,tornado模板引擎
3.1,创建一个poemmaker.py 编写视图处理逻辑
import os.path
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
class PoemPageHandler(tornado.web.RequestHandler):
def post(self):
noun1 = self.get_argument('noun1')
noun2 = self.get_argument('noun2')
verb = self.get_argument('verb')
noun3 = self.get_argument('noun3')
self.render('poem.html', roads=noun1, wood=noun2, made=verb,
difference=noun3)
if __name__ == '__main__':
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers=[
(r'/', IndexHandler),
(r'/poem', PoemPageHandler)],
template_path=os.path.join(os.path.dirname(__file__), "templates")
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
1,使用RequestHandler类的render方法来告诉Tornado读入模板文件,插入其中的模版代码,并返回结果给浏览器。 可以提供数据给模板页面显示。
2,,我们向Application对象的init方法传递了一个template_path参数。 template_path参数告诉Tornado在哪里寻找模板文件。
3.2 在对应位置创建页面模板
1,index.html
<!DOCTYPE html>
<html>
<head><title>Poem Maker Pro</title></head>
<body>
<h1>Enter terms below.</h1>
<form method="post" action="/poem">
<p>Plural noun<br><input type="text" name="noun1"></p>
<p>Singular noun<br><input type="text" name="noun2"></p>
<p>Verb (past tense)<br><input type="text" name="verb"></p>
<p>Noun<br><input type="text" name="noun3"></p>
<input type="submit">
</form>
</body>
</html>
2,poem.html
<!DOCTYPE html>
<html>
<head><title>Poem Maker Pro</title></head>
<body>
<h1>Your poem</h1>
<p>Two {{roads}} diverged in a {{wood}}, and I—<br>
I took the one less travelled by,<br>
And that has {{made}} all the {{difference}}.</p>
</body>
</html>
4,tornado模板语法
4.1,填充表达式
在代码清单2-1中,我们演示了填充Python变量的值到模板的双大括号中的使用。实际上,你可以将任何Python表达式放在双大括号中。Tornado将插入一个包含任何表达式计算结果值的字符串到输出中。类似Vue.js 双大括号语法
4.2,控制流语句
类似Java里面JSP脚本。
你同样可以在Tornado模板中使用Python条件和循环语句。控制语句以{%和%}包围,并以类似下面的形式被使用:
{% if page is None %}
或
{% if len(entries) == 3 %}
控制语句的大部分就像对应的Python语句一样工作,支持if、for、while和try。在这些情况下,语句块以{%开始,并以%}结束。
所以这个模板:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ header }}</h1>
<ul>
{% for book in books %}
<li>{{ book }}</li>
{% end %}
</ul>
</body>
</html>
当被下面这个处理函数调用时:
class BookHandler(tornado.web.RequestHandler):
def get(self):
self.render(
"book.html",
title="Home Page",
header="Books that are great",
books=[
"Learning Python",
"Programming Collective Intelligence",
"Restful Web Services"
]
)
将会渲染得到下面的输出:
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Books that are great</h1>
<ul>
<li>Learning Python</li>
<li>Programming Collective Intelligence</li>
<li>Restful Web Services</li>
</ul>
</body>
</html>
4.3,在模板中使用的函数
Tornado在所有模板中默认提供了一些便利的函数。它们包括:
escape(s)
替换字符串s中的&、<、>为他们对应的HTML字符。
url_escape(s)
使用urllib.quote_plus替换字符串s中的字符为URL编码形式。
json_encode(val)
将val编码成JSON格式。(在系统底层,这是一个对json库的dumps函数的调用。查阅相关的文档以获得更多关于该函数接收和返回参数的信息。)
squeeze(s)
过滤字符串s,把连续的多个空白字符替换成一个空格。
4.4 使用static_url生成静态URL
Tornado模板模块提供了一个叫作static_url的函数来生成static目录下文件的URL。让我们来看看在index.html中static_url的调用的示例代码:
<link rel="stylesheet" href="{{ static_url("style.css") }}">
这个对static_url的调用生成了URL的值,并渲染输出类似下面的代码:
<link rel="stylesheet" href="/static/style.css?v=ab12">
那么为什么使用static_url而不是在你的模板中硬编码呢?有如下几个原因。其一,static_url函数创建了一个基于文件内容的hash值,并将其添加到URL末尾(查询字符串的参数v)。这个hash值确保浏览器总是加载一个文件的最新版而不是之前的缓存版本。无论是在你应用的开发阶段,还是在部署到生产环境使用时,都非常有用,因为你的用户不必再为了看到你的静态内容而清除浏览器缓存了。
另一个好处是你可以改变你应用URL的结构,而不需要改变模板中的代码。例如,你可以配置Tornado响应来自像路径/s/filename.ext的请求时提供静态内容,而不是默认的/static路径。如果你使用static_url而不是硬编码的话,你的代码不需要改变。比如说,你想把静态资源从我们刚才使用的/static目录移到新的/s目录。你可以简单地改变静态路径由static变为s,然后每个使用static_url包裹的引用都会被自动更新。如果你在每个引用静态资源的文件中硬编码静态路径部分,你将不得不手动修改每个模板。
二、模板扩展
2.1 模板继承
先写一个父模板 main.html
<html>
<body>
<header>
{% block header %}{% end %}
</header>
<content>
{% block body %}{% end %}
</content>
<footer>
{% block footer %}{% end %}
</footer>
</body>
</html>
子模板覆盖父模板
{% extends "main.html" %}
{% block header %}
<h1>{{ header_text }}</h1>
{% end %}
{% block body %}
<p>Hello from the child template!</p>
{% end %}
{% block footer %}
<p>{{ footer_text }}</p>
{% end %}
相当于在父模板中提供占位,子模板继承后覆盖父模板占位部分。
2.1.1 一个例子
main.html
<html>
<head>
<title>{{ page_title }}</title>
<link rel="stylesheet" href="{{ static_url("css/style.css") }}" />
</head>
<body>
<div id="container">
<header>
{% block header %}<h1>Burt's Books</h1>{% end %}
</header>
<div id="main">
<div id="content">
{% block body %}{% end %}
</div>
</div>
<footer>
{% block footer %}
<p>
For more information about our selection, hours or events, please email us at
<a href="mailto:contact@burtsbooks.com">contact@burtsbooks.com</a>.
</p>
{% end %}
</footer>
</div>
<script src="{{ static_url("js/script.js") }}"></script>
</body>
</html>
这个页面定义了结构,应用了一个CSS样式表,并加载了主要的JavaScript文件。其他模板可以扩展它,在必要时替换header、body和footer块。
这个网站的index页(index.html)欢迎友好的网站访问者并提供一些商店的信息。通过扩展main.html,这个文件只需要包括用于替换默认文本的header和body块的信息。
index.html
{% extends "main.html" %}
{% block header %}
<h1>{{ header_text }}</h1>
{% end %}
{% block body %}
<div id="hello">
<p>Welcome to Burt's Books!</p>
<p>...</p>
</div>
{% end %}
2.2 自动转义
Tornado默认会自动转义模板中的内容,把标签转换为相应的HTML实体。这样可以防止后端为数据库的网站被恶意脚本攻击。比如,你的网站中有一个评论部分,用户可以在这里添加任何他们想说的文字进行讨论。虽然一些HTML标签在标记和样式冲突时不构成重大威胁(如评论中没有闭 h1 标签),但 script 标签会允许攻击者加载其他的JavaScript文件,打开通向跨站脚本攻击、XSS或漏洞之门。
可以使用以下方式禁用转义:
- 在 Application 构造函数中传递 autoescape=None,全局禁用。
- 在每个想要禁用的页面添加 {% autoescape None %}。
- 你可以使用{% raw %}指令来输出不转义的内容。