Tornado简介
Tornado有自己的socket(异步非阻塞,原生支持WebSocket),Django没有。
Tornado的模板语言更接近Python风格,比Django要好理解。
Demo示例
from tornado import ioloop from tornado.web import RequestHandler,Application class IndexHandler(RequestHandler): def get(self): self.write("Hello, world") application = Application([ (r"/index", IndexHandler), ]) if __name__ == "__main__": application.listen(8888) ioloop.IOLoop.instance().start()
Tornado路由系统以及通过别名反向生成url
from tornado import ioloop from tornado.web import RequestHandler,Application class IndexHandler(RequestHandler): def get(self): url1 = self.application.reverse_url(‘alias_name1‘) url2 = self.application.reverse_url(‘alias_name2‘,666) print(url1) print(url2) self.write("Hello, world") class HomeHandler(RequestHandler): def get(self,uid): print(uid) self.write("Hello, Home") application = Application([ (r"/index", IndexHandler,{},‘alias_name1‘), (r"/home/(\d+)", HomeHandler,{},‘alias_name2‘), ]) # 支持通过域名进行匹配,域名匹配到然后再匹配 url # application.add_handlers("blog.standby.pub",[ # (r"/index", IndexHandler), # (r"/home/(\d+)", HomeHandler), # ]) if __name__ == "__main__": application.listen(80) ioloop.IOLoop.instance().start()
种子管理系统
路由系统
多种方式实现登录验证
cookie
xsrf
UImethod 和 UImodule
模板引擎
目录结构
tree /f │ app.py │ my_uimethod.py │ my_uimodule.py │ ├─controllers │ account.py │ seed.py │ __init__.py │ │ ├─statics │ commons.css │ footer.css │ ├─tpl footer.html layout.html login.html seed.html video.html
app.py
from controllers.account import * from controllers.seed import * import my_uimethod import my_uimodule settings = { ‘template_path‘:‘tpl‘, ‘static_path‘:‘statics‘, ‘static_url_prefix‘:‘/static/‘, ‘xsrf_cookies‘: True, # csrf配置 ‘cookie_secret‘:‘asahcaoclacnqwncakcnal‘, ‘login_url‘:‘/login.html‘, ‘ui_methods‘:my_uimethod, ‘ui_modules‘:my_uimodule, } application = Application([ (r"/login.html", LoginHandler,{},‘login‘), (r"/logout.html", LogoutHandler,{},‘logout‘), (r"/seed.html", SeedHandler,{},‘seed‘), (r"/video.html", VideoHandler,{},‘video‘), ],**settings) if __name__ == "__main__": application.listen(80) ioloop.IOLoop.instance().start()
account.py
from tornado import ioloop from tornado.web import RequestHandler,Application class LoginHandler(RequestHandler): def get(self,*args, **kwargs): self.render(‘login.html‘,msg="") def post(self, *args, **kwargs): """ self.request 包含了所有数据: HTTPServerRequest(protocol=‘http‘, host=‘127.0.0.1‘, method=‘POST‘, uri=‘/login.html?next=%2Fseed.html‘, version=‘HTTP/1.1‘, remote_ip=‘127.0.0.1‘, headers={ ‘Content-Type‘: ‘application/x-www-form-urlencoded‘, ‘Connection‘: ‘keep-alive‘, ‘Upgrade-Insecure-Requests‘: ‘1‘, ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36‘, ‘Cache-Control‘: ‘max-age=0‘, ‘Host‘: ‘127.0.0.1‘, ‘Accept-Encoding‘: ‘gzip, deflate, br‘, ‘Origin‘: ‘http://127.0.0.1‘, ‘Content-Length‘: ‘87‘, ‘Referer‘: ‘http://127.0.0.1/login.html?next=%2Fseed.html‘, ‘Accept-Language‘: ‘zh-CN,zh;q=0.9‘, ‘Accept‘: ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8‘, ‘Cookie‘: ‘session=eyJ1c2VyX2luZm8iOiJhbGV4In0.DYUE4A.AhS8WvwJlQa8ium1YnF6tgJHwn0; _xsrf=2|50188c8e|5f181ad48a05219cb3bcf8117255223f|1520676667‘ }) """ name = self.get_argument(‘name‘) # 去GET和POST里取值 pwd = self.get_argument(‘pwd‘) args = self.get_arguments(‘name‘) # 类似Django里的 getlist() # self.get_query_argument() # 去GET里取值 # self.get_query_arguments() # 类似Django里的 getlist() # self.get_body_argument() # 去POST里取值 # self.get_body_arguments() # # 类似Django里的 getlist() if ‘alex‘ == name and ‘123‘ == pwd: import time deadline = time.time() + 3600 # self.set_cookie(‘user_info‘,name,expires=deadline) # 普通的cookie self.set_secure_cookie(‘user_info‘,name,expires=deadline) # 加盐/签名的cookie,需要在settings里配置cookie_secret # self.redirect(‘/seed.html‘) # url = self.reverse_url(‘seed‘) # self.redirect(url) # 如果使用authenticated来装饰login的get方法,并且在验证发现用户没有登录的情况下 # 则在跳转到登录页面,并会自动带上一个next字段到get请求里:http://127.0.0.1/login.html?next=%2Fseed.html next_url = self.get_query_argument(‘next‘) if not next_url: next_url = self.reverse_url(‘seed‘) self.redirect(next_url) else: self.render(‘login.html‘,msg="用户名或密码错误") class LogoutHandler(RequestHandler): def get(self,*args, **kwargs): self.write("Bye...") def post(self, *args, **kwargs): pass
seed.py
from tornado import ioloop from tornado.web import RequestHandler,Application from tornado.web import authenticated # 手写实现登录验证 # class SeedHandler(RequestHandler): # def get(self,*args, **kwargs): # # name = self.get_cookie(‘user_info‘) # name = self.get_secure_cookie(‘user_info‘) # if not name: # self.redirect(‘/login.html‘) # return # self.write("Seed!") """ 单继承 class ParentHandler(RequestHandler): # 这个方法是tornado给预留的,如果要使用 tornado.web.authenticated 来登录验证就必须自己重写这个方法 def get_current_user(self): return self.get_secure_cookie(‘user_info‘) # 使用装饰器实现登录验证 class SeedHandler(ParentHandler): @authenticated def get(self,*args, **kwargs): seed_list = [ {‘title‘:‘小麦‘,‘price‘:20}, {‘title‘:‘水稻‘,‘price‘:50}, {‘title‘:‘玉米‘,‘price‘:30} ] self.render(‘seed.html‘,seed_list=seed_list) class VideoHandler(ParentHandler): @authenticated def get(self, *args, **kwargs): video_list = [ {‘title‘: ‘柯南‘, ‘price‘: 220}, {‘title‘: ‘一人之下‘, ‘price‘: 90}, {‘title‘: ‘虫师‘, ‘price‘: 40} ] self.render(‘video.html‘, video_list=video_list) """ """ 多继承 """ class ParentHandler(object): # 这个方法是tornado给预留的,如果要使用 tornado.web.authenticated 来登录验证就必须自己重写这个方法 def get_current_user(self): return self.get_secure_cookie(‘user_info‘) # 使用装饰器实现登录验证 class SeedHandler(ParentHandler,RequestHandler): @authenticated def get(self,*args, **kwargs): seed_list = [ {‘title‘:‘小麦‘,‘price‘:20}, {‘title‘:‘水稻‘,‘price‘:50}, {‘title‘:‘玉米‘,‘price‘:30} ] self.render(‘seed.html‘,seed_list=seed_list) class VideoHandler(ParentHandler,RequestHandler): @authenticated def get(self, *args, **kwargs): video_list = [ {‘title‘: ‘柯南‘, ‘price‘: 220}, {‘title‘: ‘一人之下‘, ‘price‘: 90}, {‘title‘: ‘虫师‘, ‘price‘: 40} ] self.render(‘video.html‘, video_list=video_list)
自定义UIMethod以UIModule
def tab(self): """ 在html页面里的调用方式: {{ tab() }} {% raw tab() %} """ # print(self) # <controllers.seed.VideoHandler object at 0x000000000360D6A0> # return ‘UIMethod‘ return "<a href=‘http://www.baidu.com‘>百度</a>" def sum(self, num1, num2): return num1+num2
from tornado.web import UIModule from tornado import escape class Custom(UIModule): def render(self, *args, **kwargs): print(self,args,kwargs) return "UIModule 不仅可以返回内容还可以引入/嵌入 css和js,可以用来做一个自定制的组合模块,比如分页,只需要在使用的时候引入下就可以。" # 引入css def css_files(self): return ["/static/footer.css",] # 嵌入css def embedded_css(self): tpm = """ .foot{ height: 80px; } """ return tpm # 引入js def javascript_files(self): return ["/static/common.js",] # 嵌入js def embedded_javascript(self): tpm =""" v = 123; console.log(v); """ return tpm
seed.html
{% extends layout.html %} {% block content %} <h1>种子列表</h1> {% module Custom(123) %} <ul> {% for item in seed_list %} <li> {{ item[‘title‘] }} - {{ item[‘price‘] }}</li> <li> {{ item.get(‘title‘,‘‘) }} - {{ item.get(‘price‘,‘‘) }}</li> {% end %} </ul> {% include ‘footer.html‘ %} {% end %}
video.html
{% extends layout.html %} {% block content %} <h1>视频列表 {{ sum(1,3) }}</h1> {{ tab() }} {% raw tab() %} <ul> {% for item in video_list %} <li> {{ item[‘title‘] }} - {{ item[‘price‘] }}</li> <li> {{ item.get(‘title‘,‘‘) }} - {{ item.get(‘price‘,‘‘) }}</li> {% end %} </ul> {% end %}
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--<link rel="stylesheet" href="/static/commons.css">--> <link rel="stylesheet" href="{{ static_url(‘commons.css‘) }}"> </head> <body> <h1 class="c1">Login</h1> <form action="" method="post"> {% raw xsrf_form_html() %} <input type="text" name="name"> <input type="text" name="pwd"> <input type="submit" value="提交"> {{ msg }} </form> </body> </html>
更多请参考:http://www.cnblogs.com/wupeiqi/articles/5702910.html