xml地图|网站地图|网站标签 [设为首页] [加入收藏]

tornado框架之路二

来源:http://www.ccidsi.com 作者:集成介绍 人气:168 发布时间:2019-10-04
摘要:在ruby中cookie与任何编制程序语言同样,有expires,domain,path,secure,name那一个参谋,下边先看个简单cookie实例。 二、路由系统 Web框架之Tornado,webtornado cookie和session保存的都以字符串,别的

在ruby中cookie与任何编制程序语言同样,有expires,domain,path,secure,name那一个参谋,下边先看个简单cookie实例。

二、路由系统

Web框架之Tornado,webtornado

cookie和session保存的都以字符串,别的体系的数据类型会强制转换来字符串的情势,所以,假诺想要要在cookie或session保存对象数据,必得先将其转化成比特流格局,访谈的时候再将其转变来对象的款式,那样技艺在cookie或session中传递对象数据
#!/usr/bin/ruby

路由系统实际正是 url 和 类 的应和关系,这里分裂于其余框架,别的大多框架均是 url 对应 函数,Tornado中每一种url对应的是一个类。

概述

Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其有关工具的开源版本。这些 Web 框架看起来有一点点像web.py 或然 谷歌 的 webapp,但是为了能使得利用非阻塞式服务器境况,这几个 Web 框架还带有了有个别休戚相关的管事工具 和优化。

Tornado 和现行反革命的主流 Web 服务器框架(蕴含超越59% Python 的框架)有着明显的不一样:它是非阻塞式服务器,何况速度卓越快。得利于其 非阻塞的情势和对 epoll 的选择,Tornado 每秒能够管理数以千计的连接,那意味着对于实时 Web 服务以来,Tornado 是三个上佳的 Web 框架。大家付出那些 Web 服务器的根本指标就是为了处理FriendFeed 的实时成效 ——在 FriendFeed 的使用里每三个移动客户都会维持着一个服务器连接。(关于怎么样扩大容积服务器,以拍卖数以千计的顾客端的接连的标题,请参阅 C10K problem。)

下载安装:

pip3 install tornado

源码安装
https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

require "cgi"
cgi = CGI.new("html4")
cookie = CGI::Cookie.new('name' => 'mycookie',
                         'value' => 'Zara Ali',
                         'expires' => Time.now 3600)
cgi.out('cookie' => cookie) do
   cgi.head cgi.body { "Cookie stored" }
end


授予cookie赋值方法


class HelloController < ApplicationController
      def set_cookie
            cookies[:my_name] = "AAAA"
            redirect_to :action => "show_cookie"
      end
      def show_cookie
            my_name = cookies[:my_name]
            render(:text => "Hello #{my_name}!")
      end
end

输出全数cookie

#!/usr/bin/ruby

require "cgi"
cgi = CGI.new("html4")
cookie = cgi.cookies['mycookie']
cgi.out('cookie' => cookie) do
   cgi.head cgi.body { "Flavor: " cookie[0] }
end

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")



class WorkHanlder(tornado.web.RequestHandler): 
    def get(self,page): 
     self.write(page)


class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story "   story_id)


class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")


application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9] )", StoryHandler),
   (r"/work/(?P<page>d*)",WorkHanlder),
])


application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])


if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

框架使用

一、神速上手

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/index", MainHandler),
])


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

实施进度:

  • 先是步:实施脚本,监听 8888 端口
  • 其次步:浏览器客商端访谈 /index  -->  
  • 其三步:服务器接受诉求,并付诸对应的类管理该央求
  • 第四步:类接受到乞求之后,依据诉求格局(post / get / delete ...)的不等调用并试行相应的法子
  • 第五步:方法重回值的字符串内容发送浏览器

图片 1#!/usr/bin/env python # -*- coding:utf-8 -*- #!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from tornado import httpclient from tornado.web import asynchronous from tornado import gen import uimodules as md import uimethods as mt class MainHandler(tornado.web.RequestHandler): @asynchronous @gen.coroutine def get(self): print 'start get ' http = httpclient.AsyncHTTPClient() http.fetch("", self.callback) self.write('end') def callback(self, response): print response.body settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'ui_methods': mt, 'ui_modules': md, } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8009) tornado.ioloop.IOLoop.instance().start() 异步非阻塞示例 异步非阻塞示例

二、路由系统

路由系统实际正是 url 和 类 的应和关系,这里区别于别的框架,其余比很多框架均是 url 对应 函数,Tornado中每种url对应的是贰个类。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story "   story_id)

class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")

application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9] )", StoryHandler),
])

application.add_handlers('buy.wupeiqi.com$', [
    (r'/index',BuyHandler),
])

if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()

  Tornado中原生扶助二级域名的路由,如:

图片 2

三、模板引擎

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入在那之中,最后赢得到贰个全体的字符串,再将字符串再次来到给央浼者。

Tornado 的沙盘扶助“调控语句”和“表明语句”,调整语句是利用 {% 和 %} 包起来的 举个例子 {% if len(items) > 2 %}。表明语句是接纳 {{ 和 }} 包起来的,比如 {{ items[0] }}

支配语句和相应的 Python 语句的格式基本完全同样。大家支撑 ifforwhile 和 try,这么些讲话逻辑甘休的职位需求用 {% end %} 做标记。还通过 extends 和 block 语句完成了模版传承。那几个在 template 模块 的代码文书档案中负有详细的叙说。

注:在使用模板前须要在setting中装置模板路线:"template_path" : "tpl"

1、基本接纳

图片 3#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render("index.html", list_info = [11,22,33]) application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() app.py app.py 图片 4<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>老男孩</title> <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> </head> <body> <div> <ul> {% for item in list_info %} <li>{{item}}</li> {% end %} </ul> </div> <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> </body> </html> index.html index.html 图片 5在模板中私下认可提供了一部分函数、字段、类以供模板使用: escape: tornado.escape.xhtml_escape 的別名 xhtml_escape: tornado.escape.xhtml_escape 的別名 url_escape: tornado.escape.url_escape 的別名 json_encode: tornado.escape.json_encode 的別名 squeeze: tornado.escape.squeeze 的別名 linkify: tornado.escape.linkify 的別名 datetime: Python 的 datetime 模组 handler: 当前的 RequestHandler 对象 request: handler.request 的別名 current_user: handler.current_user 的別名 locale: handler.locale 的別名 _: handler.locale.translate 的別名 static_url: for handler.static_url 的別名 xsrf_form_html: handler.xsrf_form_html 的別名 其余措施 别的措施

2、母版

图片 6<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>老男孩</title> <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> {% block CSS %}{% end %} </head> <body> <div class="pg-header"> </div> {% block RenderBody %}{% end %} <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> {% block JavaScript %}{% end %} </body> </html> layout.html layout.html 图片 7{% extends 'layout.html'%} {% block CSS %} <link href="{{static_url("css/index.css")}}" rel="stylesheet" /> {% end %} {% block RenderBody %} <h1>Index</h1> <ul> {% for item in li %} <li>{{item}}</li> {% end %} </ul> {% end %} {% block JavaScript %} {% end %} index.html index.html

3、导入

图片 8<div> <ul> <li>1024</li> <li>42区</li> </ul> </div> header.html header.html 图片 9<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>老男孩</title> <link href="{{static_url("css/common.css")}}" rel="stylesheet" /> </head> <body> <div class="pg-header"> {% include 'header.html' %} </div> <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script> </body> </html> index.html index.html

4、自定义UIMethod以UIModule

a. 定义

图片 10# uimethods.py def tab(self): return 'UIMethod' uimethods.py 图片 11#!/usr/bin/env python # -*- coding:utf-8 -*- from tornado.web import UIModule from tornado import escape class custom(UIModule): def render(self, *args, **kwargs): return escape.xhtml_escape('<h1>wupeiqi</h1>') #return escape.xhtml_escape('<h1>wupeiqi</h1>') uimodules.py uimodules.py

b. 注册

图片 12#!/usr/bin/env python # -*- coding:utf-8 -*- #!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from tornado.escape import linkify import uimodules as md import uimethods as mt class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'ui_methods': mt, 'ui_modules': md, } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8009) tornado.ioloop.IOLoop.instance().start() View Code

c. 使用

图片 13<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url("commons.css")}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> {% module custom(123) %} {{ tab() }} </body> View Code

四、静态文件

对此静态文件,能够配备静态文件的目录和前段使用时的前缀,而且Tornaodo还援助静态文件缓存。

图片 14#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('home/index.html') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(80) tornado.ioloop.IOLoop.instance().start() app.py app.py 图片 15<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url("commons.css")}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> </body> </html> index.html index.html

注:静态文件缓存的贯彻

图片 16def get_content_version(cls, abspath): """Returns a version string for the resource at the given path. This class method may be overridden by subclasses. The default implementation is a hash of the file's contents. .. versionadded:: 3.1 """ data = cls.get_content(abspath) hasher = hashlib.md5() if isinstance(data, bytes): hasher.update(data) else: for chunk in data: hasher.update(chunk) return hasher.hexdigest() View Code

五、cookie

Tornado中得以对cookie实行操作,并且还足以对cookie实行具名以放置伪造。

1、基本操作

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_cookie("mycookie"):
            self.set_cookie("mycookie", "myvalue")
            self.write("Your cookie was not set yet!")
        else:
            self.write("Your cookie was set!")

2、加密cookie(签名)

Cookie 很轻松被恶意的客商端伪造。到场你想在 cookie 中保存当前登录客户的 id 之类的音信,你供给对 cookie 作具名以免御伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接帮忙了这种作用。 要使用那么些办法,你须要在创制应用时提供贰个密钥,名称为 cookie_secret。 你能够把它当作四个重大词参数传入应用的设置中:

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_secure_cookie("mycookie"):
            self.set_secure_cookie("mycookie", "myvalue")
            self.write("Your cookie was not set yet!")
        else:
            self.write("Your cookie was set!")

application = tornado.web.Application([
    (r"/", MainHandler),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")

图片 17def _create_signature_v1(secret, *parts): hash = hmac.new(utf8(secret), digestmod=hashlib.sha1) for part in parts: hash.update(utf8(part)) return utf8(hash.hexdigest()) # 加密 def _create_signature_v2(secret, s): hash = hmac.new(utf8(secret), digestmod=hashlib.sha256) hash.update(utf8(s)) return utf8(hash.hexdigest()) def create_signed_value(secret, name, value, version=None, clock=None, key_version=None): if version is None: version = DEFAULT_SIGNED_VALUE_VERSION if clock is None: clock = time.time timestamp = utf8(str(int(clock()))) value = base64.b64encode(utf8(value)) if version == 1: signature = _create_signature_v1(secret, name, value, timestamp) value = b"|".join([value, timestamp, signature]) return value elif version == 2: # The v2 format consists of a version number and a series of # length-prefixed fields "%d:%s", the last of which is a # signature, all separated by pipes. All numbers are in # decimal format with no leading zeros. The signature is an # HMAC-SHA256 of the whole string up to that point, including # the final pipe. # # The fields are: # - format version (i.e. 2; no length prefix) # - key version (integer, default is 0) # - timestamp (integer seconds since epoch) # - name (not encoded; assumed to be ~alphanumeric) # - value (base64-encoded) # - signature (hex-encoded; no length prefix) def format_field(s): return utf8("%d:" % len(s)) utf8(s) to_sign = b"|".join([ b"2", format_field(str(key_version or 0)), format_field(timestamp), format_field(name), format_field(value), b'']) if isinstance(secret, dict): assert key_version is not None, 'Key version must be set when sign key dict is used' assert version >= 2, 'Version must be at least 2 for key version support' secret = secret[key_version] signature = _create_signature_v2(secret, to_sign) return to_sign signature else: raise ValueError("Unsupported version %d" % version) # 解密 def _decode_signed_value_v1(secret, name, value, max_age_days, clock): parts = utf8(value).split(b"|") if len(parts) != 3: return None signature = _create_signature_v1(secret, name, parts[0], parts[1]) if not _time_independent_equals(parts[2], signature): gen_log.warning("Invalid cookie signature %r", value) return None timestamp = int(parts[1]) if timestamp < clock() - max_age_days * 86400: gen_log.warning("Expired cookie %r", value) return None if timestamp > clock() 31 * 86400: # _cookie_signature does not hash a delimiter between the # parts of the cookie, so an attacker could transfer trailing # digits from the payload to the timestamp without altering the # signature. For backwards compatibility, sanity-check timestamp # here instead of modifying _cookie_signature. gen_log.warning("Cookie timestamp in future; possible tampering %r", value) return None if parts[1].startswith(b"0"): gen_log.warning("Tampered cookie %r", value) return None try: return base64.b64decode(parts[0]) except Exception: return None def _decode_fields_v2(value): def _consume_field(s): length, _, rest = s.partition(b':') n = int(length) field_value = rest[:n] # In python 3, indexing bytes returns small integers; we must # use a slice to get a byte string as in python 2. if rest[n:n 1] != b'|': raise ValueError("malformed v2 signed value field") rest = rest[n 1:] return field_value, rest rest = value[2:] # remove version number key_version, rest = _consume_field(rest) timestamp, rest = _consume_field(rest) name_field, rest = _consume_field(rest) value_field, passed_sig = _consume_field(rest) return int(key_version), timestamp, name_field, value_field, passed_sig def _decode_signed_value_v2(secret, name, value, max_age_days, clock): try: key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value) except ValueError: return None signed_string = value[:-len(passed_sig)] if isinstance(secret, dict): try: secret = secret[key_version] except KeyError: return None expected_sig = _create_signature_v2(secret, signed_string) if not _time_independent_equals(passed_sig, expected_sig): return None if name_field != utf8(name): return None timestamp = int(timestamp) if timestamp < clock() - max_age_days * 86400: # The signature has expired. return None try: return base64.b64decode(value_field) except Exception: return None def get_signature_key_version(value): value = utf8(value) version = _get_version(value) if version < 2: return None try: key_version, _, _, _, _ = _decode_fields_v2(value) except ValueError: return None return key_version 内部算法 内部算法

签字Cookie的本色是:

写cookie过程:
  • 将值实行base64加密
  • 对除值以外的开始和结果打开签订协议,哈希算法(不能够逆向深入分析)
  • 拼接 签名 加密值

读cookie过程:

  • 读取 签名 加密值
  • 对签名进行验证
  • base64解密,获取值内容

注:多数API验证机制和安全cookie的兑现机制同样。

图片 18#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): login_user = self.get_secure_cookie("login_user", None) if login_user: self.write(login_user) else: self.redirect('/login') class LoginHandler(tornado.web.RequestHandler): def get(self): self.current_user() self.render('login.html', **{'status': ''}) def post(self, *args, **kwargs): username = self.get_argument('name') password = self.get_argument('pwd') if username == 'wupeiqi' and password == '123': self.set_secure_cookie('login_user', '武沛齐') self.redirect('/') else: self.render('login.html', **{'status': '客商名或密码错误'}) settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh' } application = tornado.web.Application([ (r"/index", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() 基于库克ie完结客户验证-德姆o 基于Cookie达成客商验证-德姆o 图片 19#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie("login_user") class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): login_user = self.current_user self.write(login_user) class LoginHandler(tornado.web.RequestHandler): def get(self): self.current_user() self.render('login.html', **{'status': ''}) def post(self, *args, **kwargs): username = self.get_argument('name') password = self.get_argument('pwd') if username == 'wupeiqi' and password == '123': self.set_secure_cookie('login_user', '武沛齐') self.redirect('/') else: self.render('login.html', **{'status': '客商名或密码错误'}) settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 'login_url': '/login' } application = tornado.web.Application([ (r"/index", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() 基于签订合同Cookie实现客户验证-德姆o 基于签字Cookie完毕客户验证-德姆o

3、JavaScript操作Cookie

是因为Cookie保存在浏览器端,所以在浏览器端也足以运用JavaScript来操作Cookie。

/*
设置cookie,指定秒数过期
 */
function setCookie(name,value,expires){
    var temp = [];
    var current_date = new Date();
    current_date.setSeconds(current_date.getSeconds()   5);
    document.cookie = name   "= "  value  ";expires="   current_date.toUTCString();
}

对于参数:

  • domain   钦命域名下的cookie
  • path       域名下钦命url中的cookie
  • secure    https使用

注:jQuery中也可以有内定的插件 jQuery Cookie 特意用来操作cookie,猛击这里

六、CSRF

Tornado中的夸张哀告伪造和Django中的相似,跨站伪造恳求(Cross-site request forgery)

图片 20settings = { "xsrf_cookies": True, } application = tornado.web.Application([ (r"/", MainHandler), (r"/login", LoginHandler), ], **settings) 配置 配置 图片 21<form action="/new_message" method="post"> {{ xsrf_form_html() }} <input type="text" name="message"/> <input type="submit" value="Post"/> </form> 普通表单 图片 22function getCookie(name) { var r = document.cookie.match("\b" name "=([^;]*)\b"); return r ? r[1] : undefined; } jQuery.postJSON = function(url, args, callback) { args._xsrf = getCookie("_xsrf"); $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST", success: function(response) { callback(eval("(" response ")")); }}); }; 使用 - AJAX 使用 - AJAX

注:Ajax使用时,本质上正是去赢得本地的cookie,指点cookie再来发送须要

七、上传文件

1、Form表单上传

图片 23<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>上传文件</title> </head> <body> <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" > <input name="fff" id="my_file" type="file" /> <input type="submit" value="提交" /> </form> </body> </html> HTML HTML

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):

        self.render('index.html')

    def post(self, *args, **kwargs):
        file_metas = self.request.files["fff"]
        # print(file_metas)
        for meta in file_metas:
            file_name = meta['filename']
            with open(file_name,'wb') as up:
                up.write(meta['body'])

settings = {
    'template_path': 'template',
}

application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()

Python

 2、AJAX上传

图片 24<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script> function UploadFile(){ var fileObj = document.getElementById("img").files[0]; var form = new FormData(); form.append("k1", "v1"); form.append("fff", fileObj); var xhr = new XMLHttpRequest(); xhr.open("post", '/index', true); xhr.send(form); } </script> </body> </html> HTML - XMLHttpRequest HTML - XMLHttpRequest 图片 25<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" /> <script> function UploadFile(){ var fileObj = $("#img")[0].files[0]; var form = new FormData(); form.append("k1", "v1"); form.append("fff", fileObj); $.ajax({ type:'POST', url: '/index', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg){ console.log(arg); } }) } </script> </body> </html> HTML - jQuery View Code 图片 26<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <form id="my_form" name="form" action="/index" method="POST" enctype="multipart/form-data" > <div id="main"> <input name="fff" id="my_file" type="file" /> <input type="button" name="action" value="Upload" onclick="redirect()"/> <iframe id='my_iframe' name='my_iframe' src="" class="hide"></iframe> </div> </form> <script> function redirect(){ document.getElementById('my_iframe').onload = Testt; document.getElementById('my_form').target = 'my_iframe'; document.getElementById('my_form').submit(); } function Testt(ths){ var t = $("#my_iframe").contents().find("body").text(); console.log(t); } </script> </body> </html> HTML - iframe HTML - iframe 图片 27#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): file_metas = self.request.files["fff"] # print(file_metas) for meta in file_metas: file_name = meta['filename'] with open(file_name,'wb') as up: up.write(meta['body']) settings = { 'template_path': 'template', } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start() Python Python 图片 28<script type="text/javascript"> $(document).ready(function () { $("#formsubmit").click(function () { var iframe = $('<iframe name="postiframe" id="postiframe">'); $("body").append(iframe); var form = $('#theuploadform'); form.attr("action", "/upload.aspx"); form.attr("method", "post"); form.attr("encoding", "multipart/form-data"); form.attr("enctype", "multipart/form-data"); form.attr("target", "postiframe"); form.attr("file", $('#userfile').val()); form.submit(); $("#postiframe").load(function () { iframeContents = this.contentWindow.document.body.innerHTML; $("#textarea").html(iframeContents); }); return false; }); }); </script> <form id="theuploadform"> <input id="userfile" name="userfile" size="50" type="file" /> <input id="formsubmit" type="submit" value="Send File" /> </form> <div id="textarea"> </div> 扩充:基于iframe达成Ajax上传示例 扩张:基于iframe实现Ajax上传示例

八、验证码

验证码原理在于后台自动创立一张带有随机内容的图纸,然后将内容通过img标签输出到页面。

安装图像管理模块:pip3 install pillow

亲自去做截图:图片 29

class CheckCodeHandler(BaseRequestHandler):
    def get(self, *args, **kwargs):
        stream = io.BytesIO()
        img, code = check_code.create_validate_code()
        img.save(stream, "png")
        self.session["CheckCode"] = code
        self.write(stream.getvalue())
Attribute Returned Value
name Cookie name
value An array of cookie values
path The cookie's path
domain The domain
expires The expiration time (as a Time object)
secure True if secure cookie

分页(一页展现五条内容,每页展现10个页码)

自定义Web组件

一、Session

1、面向对象基础

面向对象中经过索引的主意访谈对象,必要中间贯彻 __getitem__ 、__delitem__、__setitem__方法

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

    def __getitem__(self, key):
        print  '__getitem__',key

    def __setitem__(self, key, value):
        print '__setitem__',key,value

    def __delitem__(self, key):
        print '__delitem__',key



obj = Foo()
result = obj['k1']
#obj['k2'] = 'wupeiqi'
#del obj['k1']

2、Tornado扩展

Tornado框架中,私下认可推行Handler的get/post等措施此前私下认可会施行initialize方法,所以可以经过自定义的不二等秘书技使得全部央浼在拍卖前实行操作...

class BaseHandler(tornado.web.RequestHandler):

    def initialize(self):
        self.xxoo = "wupeiqi"


class MainHandler(BaseHandler):

    def get(self):
        print(self.xxoo)
        self.write('index')

class IndexHandler(BaseHandler):

    def get(self):
        print(self.xxoo)
        self.write('index')

3、session

session其实正是概念在服务器端用于保存顾客作答的容器,其必需信任cookie技艺促成。

图片 30#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from hashlib import sha1 import os, time session_container = {} create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest() class Session(object): session_id = "__sessionId__" def __init__(self, request): session_value = request.get_cookie(Session.session_id) if not session_value: self._id = create_session_id() else: self._id = session_value request.set_cookie(Session.session_id, self._id) def __getitem__(self, key): return session_container[self._id][key] def __setitem__(self, key, value): if session_container.has_key(self._id): session_container[self._id][key] = value else: session_container[self._id] = {key: value} def __delitem__(self, key): del session_container[self._id][key] class BaseHandler(tornado.web.RequestHandler): def initialize(self): # my_session['k1']访问 __getitem__ 方法 self.my_session = Session(self) class MainHandler(BaseHandler): def get(self): print self.my_session['c_user'] print self.my_session['c_card'] self.write('index') class LoginHandler(BaseHandler): def get(self): self.render('login.html', **{'status': ''}) def post(self, *args, **kwargs): username = self.get_argument('name') password = self.get_argument('pwd') if username == 'wupeiqi' and password == '123': self.my_session['c_user'] = 'wupeiqi' self.my_session['c_card'] = '12312312309823012' self.redirect('/index') else: self.render('login.html', **{'status': '顾客名或密码错误'}) settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 'login_url': '/login' } application = tornado.web.Application([ (r"/index", MainHandler), (r"/login", LoginHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() 自定义Session 自定义Session

4、分布式Session

图片 31#!/usr/bin/env python #coding:utf-8 import sys import math from bisect import bisect if sys.version_info >= (2, 5): import hashlib md5_constructor = hashlib.md5 else: import md5 md5_constructor = md5.new class HashRing(object): """一致性哈希""" def __init__(self,nodes): '''伊始化 nodes : 开头化的节点,当中包涵节点已经节点对应的权重 暗许每一个节点有三13个虚构节点 对于权重,通过多创设设想节点来贯彻 如:nodes = [ {'host':'127.0.0.1:8000','weight':1}, {'host':'127.0.0.1:8001','weight':2}, {'host':'127.0.0.1:8002','weight':1}, ] ''' self.ring = dict() self._sorted_keys = [] self.total_weight = 0 self.__generate_circle(nodes) def __generate_circle(self,nodes): for node_info in nodes: self.total_weight = node_info.get('weight',1) for node_info in nodes: weight = node_info.get('weight',1) node = node_info.get('host',None) virtual_node_count = math.floor((32*len(nodes)*weight) / self.total_weight) for i in xrange(0,int(virtual_node_count)): key = self.gen_key_thirty_two( '%s-%s' % (node, i) ) if self._sorted_keys.__contains__(key): raise Exception('该节点已经存在.') self.ring[key] = node self._sorted_keys.append(key) def add_node(self,node): ''' 新建节点 node : 要加多的节点,格式为:{'host':'127.0.0.1:8002','weight':1},当中第一个成分表示节点,第三个因素表示该节点的权重。 ''' node = node.get('host',None) if not node: raise Exception('节点的地址无法为空.') weight = node.get('weight',1) self.total_weight = weight nodes_count = len(self._sorted_keys) 1 virtual_node_count = math.floor((32 * nodes_count * weight) / self.total_weight) for i in xrange(0,int(virtual_node_count)): key = self.gen_key_thirty_two( '%s-%s' % (node, i) ) if self._sorted_keys.__contains__(key): raise Exception('该节点已经存在.') self.ring[key] = node self._sorted_keys.append(key) def remove_node(self,node): ''' 移除节点 node : 要移除的节点 '127.0.0.1:七千' ''' for key,value in self.ring.items(): if value == node: del self.ring[key] self._sorted_keys.remove(key) def get_node(self,string_key): '''获取 string_key 所在的节点''' pos = self.get_node_pos(string_key) if pos is None: return None return self.ring[ self._sorted_keys[pos]].split(':') def get_node_pos(self,string_key): '''获取 string_key 所在的节点的索引''' if not self.ring: return None key = self.gen_key_thirty_two(string_key) nodes = self._sorted_keys pos = bisect(nodes, key) return pos def gen_key_thirty_two(self, key): m = md5_constructor() m.update(key) return long(m.hexdigest(), 16) def gen_key_sixteen(self,key): b_key = self.__hash_digest(key) return self.__hash_val(b_key, lambda x: x) def __hash_val(self, b_key, entry_fn): return (( b_key[entry_fn(3)] << 24)|(b_key[entry_fn(2)] << 16)|(b_key[entry_fn(1)] << 8)| b_key[entry_fn(0)] ) def __hash_digest(self, key): m = md5_constructor() m.update(key) return map(ord, m.digest()) """ nodes = [ {'host':'127.0.0.1:8000','weight':1}, {'host':'127.0.0.1:8001','weight':2}, {'host':'127.0.0.1:8002','weight':1}, ] ring = HashRing(nodes) result = ring.get_node('98708798709870987098709879087') print result """ 一致性哈西 一致性哈西 图片 32from hashlib import sha1 import os, time create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest() class Session(object): session_id = "__sessionId__" def __init__(self, request): session_value = request.get_cookie(Session.session_id) if not session_value: self._id = create_session_id() else: self._id = session_value request.set_cookie(Session.session_id, self._id) def __getitem__(self, key): # 根据 self._id ,在一致性哈西中找到其相应的服务器IP # 找到相对应的redis服务器,如: r = redis.StrictRedis(host='localhost', port=6379, db=0) # 使用python redis api 链接 # 获取数据,即: # return self._redis.hget(self._id, name) def __setitem__(self, key, value): # 根据 self._id ,在一致性哈西中找到其相应的服务器IP # 使用python redis api 链接 # 设置session # self._redis.hset(self._id, name, value) def __delitem__(self, key): # 根据 self._id 找到相对应的redis服务器 # 使用python redis api 链接 # 删除,即: return self._redis.hdel(self._id, name) session session

二、表单验证

在Web程序中反复含有多量的表单验证的行事,如:判别输入是不是为空,是或不是顺应准则。

图片 33<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <link href="{{static_url("commons.css")}}" rel="stylesheet" /> </head> <body> <h1>hello</h1> <form action="/index" method="post"> <p>hostname: <input type="text" name="host" /> </p> <p>ip: <input type="text" name="ip" /> </p> <p>port: <input type="text" name="port" /> </p> <p>phone: <input type="text" name="phone" /> </p> <input type="submit" /> </form> </body> </html> HTML HTML 图片 34#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web from hashlib import sha1 import os, time import re class MainForm(object): def __init__(self): self.host = "(.*)" self.ip = "^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$" self.port = '(d )' self.phone = '^1[3|4|5|8][0-9]d{8}$' def check_valid(self, request): form_dict = self.__dict__ for key, regular in form_dict.items(): post_value = request.get_argument(key) # 让提交的数据 和 定义的正则表达式进行相配 ret = re.match(regular, post_value) print key,ret,post_value class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): obj = MainForm() result = obj.check_valid(self) self.write('ok') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 'login_url': '/login' } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() Python Python

鉴于验证准则能够代码重用,所以能够这么定义:

图片 35#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web import re class Field(object): def __init__(self, error_msg_dict, required): self.id_valid = False self.value = None self.error = None self.name = None self.error_msg = error_msg_dict self.required = required def match(self, name, value): self.name = name if not self.required: self.id_valid = True self.value = value else: if not value: if self.error_msg.get('required', None): self.error = self.error_msg['required'] else: self.error = "%s is required" % name else: ret = re.match(self.REGULAR, value) if ret: self.id_valid = True self.value = ret.group() else: if self.error_msg.get('valid', None): self.error = self.error_msg['valid'] else: self.error = "%s is invalid" % name class IPField(Field): REGULAR = "^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$" def __init__(self, error_msg_dict=None, required=True): error_msg = {} # {'required': 'IP无法为空', 'valid': 'IP格式错误'} if error_msg_dict: error_msg.update(error_msg_dict) super(IPField, self).__init__(error_msg_dict=error_msg, required=required) class IntegerField(Field): REGULAR = "^d $" def __init__(self, error_msg_dict=None, required=True): error_msg = {'required': '数字无法为空', 'valid': '数字格式错误'} if error_msg_dict: error_msg.update(error_msg_dict) super(IntegerField, self).__init__(error_msg_dict=error_msg, required=required) class CheckBoxField(Field): def __init__(self, error_msg_dict=None, required=True): error_msg = {} # {'required': 'IP不可能为空', 'valid': 'IP格式错误'} if error_msg_dict: error_msg.update(error_msg_dict) super(CheckBoxField, self).__init__(error_msg_dict=error_msg, required=required) def match(self, name, value): self.name = name if not self.required: self.id_valid = True self.value = value else: if not value: if self.error_msg.get('required', None): self.error = self.error_msg['required'] else: self.error = "%s is required" % name else: if isinstance(name, list): self.id_valid = True self.value = value else: if self.error_msg.get('valid', None): self.error = self.error_msg['valid'] else: self.error = "%s is invalid" % name class FileField(Field): REGULAR = "^(w .pdf)|(w .mp3)|(w .py)$" def __init__(self, error_msg_dict=None, required=True): error_msg = {} # {'required': '数字不可能为空', 'valid': '数字格式错误'} if error_msg_dict: error_msg.update(error_msg_dict) super(FileField, self).__init__(error_msg_dict=error_msg, required=required) def match(self, name, value): self.name = name self.value = [] if not self.required: self.id_valid = True self.value = value else: if not value: if self.error_msg.get('required', None): self.error = self.error_msg['required'] else: self.error = "%s is required" % name else: m = re.compile(self.REGULAR) if isinstance(value, list): for file_name in value: r = m.match(file_name) if r: self.value.append(r.group()) self.id_valid = True else: self.id_valid = False if self.error_msg.get('valid', None): self.error = self.error_msg['valid'] else: self.error = "%s is invalid" % name break else: if self.error_msg.get('valid', None): self.error = self.error_msg['valid'] else: self.error = "%s is invalid" % name def save(self, request, upload_path=""): file_metas = request.files[self.name] for meta in file_metas: file_name = meta['filename'] with open(file_name,'wb') as up: up.write(meta['body']) class Form(object): def __init__(self): self.value_dict = {} self.error_dict = {} self.valid_status = True def validate(self, request, depth=10, pre_key=""): self.initialize() self.__valid(self, request, depth, pre_key) def initialize(self): pass def __valid(self, form_obj, request, depth, pre_key): """ 验证客商表单伏乞的数据 :param form_obj: Form对象(Form派生类的靶子) :param request: Http必要上下文(用于从呼吁中得到客户提交的值) :param depth: 对Form内容的深浅的协理 :param pre_key: Html中name属性值的前缀(多层Form时,内部递归时设置,没有要求理会) :return: 是不是表明通过,True:验证成功;False:验证退步 """ depth -= 1 if depth < 0: return None form_field_dict = form_obj.__dict__ for key, field_obj in form_field_dict.items(): print key,field_obj if isinstance(field_obj, Form) or isinstance(field_obj, Field): if isinstance(field_obj, Form): # 获取以key初阶的装有的值,以参数的方式传至 self.__valid(field_obj, request, depth, key) continue if pre_key: key = "%s.%s" % (pre_key, key) if isinstance(field_obj, CheckBoxField): post_value = request.get_arguments(key, None) elif isinstance(field_obj, FileField): post_value = [] file_list = request.request.files.get(key, None) for file_item in file_list: post_value.append(file_item['filename']) else: post_value = request.get_argument(key, None) print post_value # 让提交的数据 和 定义的正则表达式进行相配 田野_obj.match(key, post_value) if field_obj.id_valid: self.value_dict[key] = field_obj.value else: self.error_dict[key] = field_obj.error self.valid_status = False class ListForm(object): def __init__(self, form_type): self.form_type = form_type self.valid_status = True self.value_dict = {} self.error_dict = {} def validate(self, request): name_list = request.request.arguments.keys() request.request.files.keys() index = 0 flag = False while True: pre_key = "[%d]" % index for name in name_list: if name.startswith(pre_key): flag = True break if flag: form_obj = self.form_type() form_obj.validate(request, depth=10, pre_key="[%d]" % index) if form_obj.valid_status: self.value_dict[index] = form_obj.value_dict else: self.error_dict[index] = form_obj.error_dict self.valid_status = False else: break index = 1 flag = False class MainForm(Form): def __init__(self): # self.ip = IPField(required=True) # self.port = IntegerField(required=True) # self.new_ip = IPField(required=True) # self.second = SecondForm() self.fff = FileField(required=True) super(MainForm, self).__init__() # # class SecondForm(Form): # # def __init__(self): # self.ip = IPField(required=True) # self.new_ip = IPField(required=True) # # super(SecondForm, self).__init__() class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') def post(self, *args, **kwargs): # for i in dir(self.request): # print i # print self.request.arguments # print self.request.files # print self.request.query # name_list = self.request.arguments.keys() self.request.files.keys() # print name_list # list_form = ListForm(MainForm) # list_form.validate(self) # # print list_form.valid_status # print list_form.value_dict # print list_form.error_dict # obj = MainForm() # obj.validate(self) # # print "验证结果:", obj.valid_status # print "切合验证结果:", obj.value_dict # print "错误音信:" # for key, item in obj.error_dict.items(): # print key,item # print self.get_arguments('favor'),type(self.get_arguments('favor')) # print self.get_argument('favor'),type(self.get_argument('favor')) # print type(self.get_argument('fff')),self.get_argument('fff') # print self.request.files # obj = MainForm() # obj.validate(self) # print obj.valid_status # print obj.value_dict # print obj.error_dict # print self.request,type(self.request) # obj.fff.save(self.request) # from tornado.httputil import HTTPServerRequest # name_list = self.request.arguments.keys() self.request.files.keys() # print name_list # print self.request.files,type(self.request.files) # print len(self.request.files.get('fff')) # obj = MainForm() # obj.validate(self) # print obj.valid_status # print obj.value_dict # print obj.error_dict # obj.fff.save(self.request) self.write('ok') settings = { 'template_path': 'template', 'static_path': 'static', 'static_url_prefix': '/static/', 'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh', 'login_url': '/login' } application = tornado.web.Application([ (r"/index", MainHandler), ], **settings) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() View Code

 

 

 

 

 

概述 Tornado是FriendFeed使用的可扩张的非阻塞式 web 服务器及其相关工具的开源版本。这么些 Web 框架看起来有一些像we...

图片 36图片 37

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop
from work.controller import work

settings={
    "template_path":"tpl",
}

application = tornado.web.Application([
    (r"/work/(?P<page>d*)",work.WorkHanlder),
],**settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

start.py

图片 38图片 39

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
list_all = ["ssdfsdgsdsgfdf",]
for i in range(100):
    list_all.append("123士大夫是的覅是公司的")
class WorkHanlder(tornado.web.RequestHandler):
    def get(self,page):   #page指的是当前页
        list_asd = []
        try:
            page = int(page)  #如果在浏览器上输入的值为整型则正常转
        except:
            page = 1          #如果输入的值不是int型的,则默认为第一页
        start = (page - 1)*5   #内容的开始取值范围
        end = page*5           #内容的结束取值范围
        list = list_all[start:end] #根据当前页的页码,获取相应页码的内容
        all_page ,c = divmod(len(list_all),5) #每页的内容设置为5,超出时下一页显示
        if c>0:
            all_page = 1        # 如果余数大于0,说明还需要另一页来显示
        if all_page < 11:       #设置一页显示11个页码  如果总页数为小于11的话,无论点那一页默认显示全部
            s = 1               #页码开始为1
            t = all_page        #页码结束为总页码
        else:                #我们设置格式为显示前5后5
            if page < 6:        #当页码大于11的时候,又分当前页码如果小于6时,显示1-12的页码
                s = 1
                t = 12
            else:              #页码大于11且当前页码大于6时又分下面俩种
                if all_page > page  5 :    #
                    s = page - 5
                    t = page   5   1
                else:
                    s = all_page - 11
                    t = all_page   1
        for p in range(s,t):
            if p == page:
                temp = "<a href='/work/%s' style='color:red'>%s</a>"%(p,p)
            else:
                temp = "<a href='/work/%s'>%s</a>"%(p,p)
            list_asd.append(temp)
        st = "".join(list_asd)
        self.render("work.html",list_show = list ,list_page =st,)

    def post(self, *args, **kwargs):
        pass

work.py

图片 40图片 41

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for item in list_show %}
<h3>{{ item }}</h3>
{% end %}

{% raw list_page %}
</body>
</html>

work.html

css文件和js文件的引入形式

<link rel="stylesheet" href="{{static_url('chouti.css')}}">
<script src="{{static_url('jquery-1.9.1.min.js')}}"></script>

Tornado中原生扶助二级域名的路由,如:

图片 42

三、模板引擎

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入个中,最后收获到二个完好无缺的字符串,再将字符串再次回到给央求者。

Tornado 的模板接济“调节语句”和“表明语句”,调整语句是选取 {% 和 %} 包起来的 举例 {% if len(items) > 2 %}发挥语句是采取 {{ 和 }} 包起来的

,例如 {{ items[0] }}

操纵语句和相应的 Python 语句的格式基本千篇一律。大家支撑 ifforwhile 和 try,这么些讲话逻辑甘休的职分须求用 {% end %} 做标记。还通过 extends 和 block 语句完毕了模版承袭。这几个在 template 模块 的代码文书档案中有所详细的叙说。

注:在接纳模板前要求在setting中装置模板路线:"template_path" : "tpl"

1、基本使用

图片 43图片 44

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html", list_info = [11,22,33])

application = tornado.web.Application([
    (r"/index", MainHandler),
])


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

index

图片 45图片 46

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>老男孩</title>
    <link href="{{static_url("css/common.css")}}" rel="stylesheet" />
</head>
<body>

    <div>
        <ul>
            {% for item in list_info %}
                <li>{{item}}</li>
            {% end %}
        </ul>
    </div>

    <script src="{{static_url("js/jquery-1.8.2.min.js")}}"></script>

</body>
</html>

index.html

在模板中默认提供了一些函数、字段、类以供模板使用:

escape: tornado.escape.xhtml_escape 的別名
xhtml_escape: tornado.escape.xhtml_escape 的別名
url_escape: tornado.escape.url_escape 的別名
json_encode: tornado.escape.json_encode 的別名
squeeze: tornado.escape.squeeze 的別名
linkify: tornado.escape.linkify 的別名
datetime: Python 的 datetime 模组
handler: 当前的 RequestHandler 对象
request: handler.request 的別名
current_user: handler.current_user 的別名
locale: handler.locale 的別名
_: handler.locale.translate 的別名
static_url: for handler.static_url 的別名
xsrf_form_html: handler.xsrf_form_html 的別名

2、母版

内容的引进:

在母版的body块中写--------------->{% block body %}{% end %}

在子版中写------------------------{% extends 'layout.html'%} ---------->导入母版

-----------------------------------{% block body %}---------------------->格式

-----------------------------------<h1>work</h1>------------------------>内容

-----------------------------------{% end %}------------------------------>格式

图片 47图片 48

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .c1{
            height: 40px;
            background-color: #2459a2;
        }
        .c2{
            height: 40px;
            background-color: black;
        }
    </style>
</head>
<body>
<div class="c1"></div>
{% block body %}{% end %}
<div class="c2"></div>
</body>
</html>

layout.html

图片 49图片 50

{% extends 'layout.html'%}
{% block body %}
<h1>index</h1>
{% end %}

index.html

图片 51图片 52

{% extends 'layout.html'%}
{% block body %}
<h1>work</h1>
{% end %}

本文由68399皇家赌场发布于集成介绍,转载请注明出处:tornado框架之路二

关键词: 68399皇家赌场 tornado框架

最火资讯