Tornado简介
Tornado是使用Python开发的全栈式(full-stack)Web框架和异步网络库,最早由Friendfeed开发。通过使用非阻塞IO,Tornado可以处理数以万计的开放连接,是long polling、WebSockets和其他需要为用户维护长连接应用的理想选择。
Tornado 跟其他主流的Web服务器框架(主要是Python框架)不同是采用epoll非阻塞IO,响应快速,可处理数千并发连接,特别适用用于实时的Web服务。
Tornado 主要分成四个部分:
- Web 框架(包括 RequestHandler,用于创建Web程序的基类,以及各种支持类)
- 实现 HTTP 的客户端和服务器端 (HTTPServer 和 AsyncHTTPClient).
- 一个异步网络库 (IOLoop 和 IOStream)
- 一个协程库(tornado.gen) ,使得异步调用代码能够以更直接的方式书写,取代回调链接
Mac下安装tornado
自动安装
可以通过 pip 或者 easy_install 来安装。例如:
sudo easy_install tornado #安装tornado
手动安装
下载传送门:http://www.tornadoweb.cn
然后运行:
tar xvzf tornado-1.2.1.tar.gz
cd tornado-1.2.1
python setup.py build #编译安装程序
sudo python setup.py install #安装
接下来进行测试是否安装成功:
# -*- coding:utf-8 -*-
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):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', tornado!')
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
给权限后,执行./hello.py –port=1234启动服务器。
在本地浏览器打开http://localhost:1234/可以看到:
Hello, tornado!
ok,tornado环境已经搭建完成
MongoDB环境搭建(Mac)
MongoDB下载传送门:http://downloads.mongodb.org/osx/mongodb-osx-x86_64-2.6.3.tgz
解压完之后,MongoDB其实已经可以开始用了。
首先我们在mongodb目录下创建data文件夹,用来存储数据库数据。打开终端,cd到mongodb的目录中bin文件夹,运行mongod,命令如下:
./mongod --dbpath=/Users/edison/mongodb/data #mac的命令
#dbpath是数据库位置参数,这里我们使用的是刚才创建的data文件夹
大致如下:
FAQ:
–dbpath的位置权限不够,所以可能需要赋予该有的权限。
chmod -R 777 /Users/edison/mongodb/data
安装PyMongo
PyMongo 是 MongoDB 的 Python 接口开发包。我们需要安装PyMongo来获得Tornado应用使用MongoDB的能力。
自动安装:
sudo easy_install pymongo
手动安装:
下载传送门:https://pypi.python.org/pypi/pymongo/#downloads
Tenjino简介
- 多脚本语言模板引擎 Tenjin
- 号称全球最快的模板引擎
Tenjin 是一个超快而且轻量级的模板引擎,类似 eRuby ,但支持嵌套的布局模板、嵌入其他模板,捕获模板的某个部分等等,同时还支持文件缓存和内存缓存、预处理等。
提供多种脚本语言的版本,包括:Ruby, PHP, Perl, Python 和 JavaScript。
自动安装
sudo easy_install Tenjin
手动安装
下载传送门:https://pypi.python.org/pypi/Tenjin/
tar xzf Tenjin-X.X.X.tar.gz
cd Tenjin-X.X.X
sudo python setup.py install
使用指南:http://www.liujingze.com/docs/pytenjin/pytenjin-users-guide.html#
到这边所需要的环境都搭建完成了,开始写项目把!
手摸手教学之 来个demo
test1.py
#! /usr/bin/python
# -*- coding:utf-8 -*-
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import time
import os.path
import tenjin
import pymongo
# 调试模式
import tornado.autoreload
from tenjin.helpers import *
from tenjin.html import *
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):
engine = tenjin.Engine(path=['view'], postfix='.html')
table = db.mytable
blogs = table.find().sort("_id",pymongo.DESCENDING)
context = {
'blogs':blogs,
"page_title":"我的博客",
}
html = engine.render(':index', context)
self.finish(html)
class BlogHandler(tornado.web.RequestHandler):
def get(self, id=None):
engine = tenjin.Engine(path=['view'], postfix='.html')
table = db.mytable
blog = table.find_one({"id": int(id)})
context = {
'blog':blog,
"page_title":"我的博客",
}
html = engine.render(':blog', context)
self.finish(html)
class EditHandler(tornado.web.RequestHandler):
def get(self, id=None):
engine = tenjin.Engine(path=['view'], postfix='.html')
table = db.mytable
if id:
blog = table.find_one({"id": int(id)})
context = {
'blog':blog,
'type':"edit"
}
else:
context = {
'type':"add"
}
html = engine.render(':edit', context)
self.finish(html)
def post(self, id=None):
table = db.mytable
blog = dict()
if id:
blog = table.find_one({"id": int(id)})
blog['title'] = self.get_argument("title", None)
blog['content'] = self.get_argument("content", None)
if id:
table.save(blog)
else:
last = table.find().sort("id",pymongo.DESCENDING).limit(1)
lastone = dict()
for item in last:
lastone = item
blog['id'] = int(lastone['id']) + 1
blog['date'] = int(time.time())
table.insert(blog)
self.redirect("/")
class DelHandler(tornado.web.RequestHandler):
def get(self, id=None):
table = db.mytable
if id:
blog = table.remove({"id": int(id)})
self.redirect("/")
db = ""
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers=[(r'/', IndexHandler),
(r"/blog/([0-9Xx\-]+)", BlogHandler),
(r"/edit/([0-9Xx\-]+)", EditHandler),
(r"/delete/([0-9Xx\-]+)", DelHandler),
(r"/add", EditHandler),
],
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
)
client = pymongo.MongoClient()
db = client.test
# print(db)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
loop = tornado.ioloop.IOLoop.instance()
# 调试模式 仅监听py文件的改动
tornado.autoreload.start(loop)
loop.start()
index.html
<?py #@ARGS blogs, page_title ?>
<!DOCTYPE html>
<html>
<head>
<title>${page_title}</title>
<link rel="stylesheet" type="text/css" href="../static/css/style.css">
</head>
<body>
<div class="main">
<div class="container">
<h1>HTSS的博客</h1>
<?py for blog in blogs: ?>
<div class="content">
<div class="Title">
<p>
${ blog['title'] }
</p>
<p>
<span class="Time">${ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(blog['date'])) ) }</span>
</p>
</div>
<div class="Article">
<p>
<a href="blog/${ blog['id'] }">点击阅读</a>
</p>
</div>
</div>
<?py #endfor ?>
<a href="/add">
<input type="button" class="Article Button Submit" value="发布博客" onclick="document.location.href('/add/')"/>
</a>
</div>
</div>
</body>
</body>
</html>
blog.html
<?py #@ARGS blog, page_title ?>
<!DOCTYPE html>
<html>
<head>
<title>${page_title}</title>
<link rel="stylesheet" type="text/css" href="../static/css/style.css">
</head>
<body>
<div class="main">
<div class="container">
<h1><a href="/">HTSS的博客</a></h1>
<div class="content">
<div class="Title">
<p>
${ blog['title'] }
</p>
<p>
<span class="Time">${ time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(blog['date'])) ) }</span>
</p>
</div>
<div class="Article">
<p>
${ blog['content'] }
</p>
</div>
<div class="buttonDiv">
<a href="/edit/${ blog['id'] }">
<input type="button" class="Article Button Edit" value="编 辑"/>
</a>
<a href="/delete/${ blog['id'] }">
<input type="button" class="Article Button Delete" value="删 除"/>
</a>
</div>
</div>
</div>
</div>
</div>
</body>
</body>
</html>
edit.html
<?py #@ARGS blog, type ?>
<!DOCTYPE html>
<html>
<head>
<title>编辑</title>
<link rel="stylesheet" type="text/css" href="../static/css/style.css">
</head>
<body>
<div class="main">
<div class="container">
<h1><a href="/">HTSS的博客</a></h1>
<div class="content">
<?py if type == "edit": ?>
<form method="post" action="/edit/${ int(blog['id']) }">
<input type="hidden" name="id" value="${ int(blog['id']) }">
<?py else: ?>
<form method="post" action="/add">
<?py #endif ?>
<p>文章标题:</p>
<?py if type == "edit": ?>
<input type="text" class="Title" name="title" placeholder="在这里输入你的标题" value="${ blog.get('title', '') }" />
<?py else: ?>
<input type="text" class="Title" name="title" placeholder="在这里输入你的标题"/>
<?py #endif ?>
<p>文章正文:</p>
<textarea type="text" class="Article" id="myArticle" name="content" placeholder="在这里输入你的正文">
<?py if type == "edit": ?>
${ blog.get('content', '') }
<?py #endif ?>
</textarea>
<br/>
<?py if type == "edit": ?>
<input type="submit" class="Article Button Submit" value="修 改"/>
<?py else: ?>
<input type="submit" class="Article Button Submit" value="发 布"/>
<?py #endif ?>
</form>
</div>
</div>
</div>
</body>
</body>
</html>
Run!
服务器跑起来
这边我是给了port,为1234。如果不给port则是
define("port", default=8000, help="run on the given port", type=int)
此时打开浏览器,访问http://localhost:1234/,我们可以发现网站已经可以正常访问。
Handlers 和 settings
app = tornado.web.Application(
handlers=[(r'/', IndexHandler),
(r"/blog/([0-9Xx\-]+)", BlogHandler),
(r"/edit/([0-9Xx\-]+)", EditHandler),
(r"/delete/([0-9Xx\-]+)", DelHandler),
(r"/add", EditHandler),
],
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
)
handlers是用于设定url与处理类间的映射关系。
template_path用于指定我们之后要渲染的html文件的文件夹位置
用于指定之后要用的的一些引用文件(如css文件、js文件、图片等)的文件夹位置
数据库
client = pymongo.MongoClient()
db = client.test
mongodb默认是没有用户名和密码的
Hello World!
class IndexHandler(tornado.web.RequestHandler):
# 一个get请求
def get(self):
# 这个是tenjin模板
# path是要渲染的html文件的文件夹位置
# postfix是文件后缀
engine = tenjin.Engine(path=['view'], postfix='.html')
# 获取表
table = db.mytable
#查找数据 根据_id 倒序
blogs = table.find().sort("_id",pymongo.DESCENDING)
context = {
'blogs':blogs,
"page_title":"我的博客",
}
html = engine.render(':index', context)
self.finish(html)