python web框架-tornado

Web框架中的各个知识点:

Python的Web框架Tornado的源码

Python开发一个完善的MVC框架 

MVC模式

 

 
所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起:
A.模型负责业务对象与数据库的映射(ORM)
B.视图负责与用户的交互(页面)
C.控制器接受用户的输入调用模型和视图完成用户的请求
 
其示意图如下所示:
 
 

MTV模式

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同
Django的MTV分别是值:
  • M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
  • T 代表模板 (Template):负责如何把页面展示给用户(html)。
  • V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
  1. Web服务器(中间件)收到一个http请求
  2. Django在URLconf里查找对应的视图(View)函数来处理http请求
  3. 视图函数调用相应的数据模型来存取数据、调用相应的模板向用户展示页面
  4. 视图函数处理结束后返回一个http的响应给Web服务器
  5. Web服务器将响应发送给客户端

这种设计模式关键的优势在于各种组件都是松耦合的。这样,每个由 Django驱动的Web应用都有着明确的目的,并且可独立更改而不影响到其它的部分。 
比如,开发者更改一个应用程序中的 URL 而不用影响到这个程序底层的实现。设计师可以改变 HTML页面的样式而不用接触Python代码。
数据库管理员可以重新命名数据表并且只需更改模型,无需从一大堆文件中进行查找和替换。
 
Django的MTV模式相对应的python文件如下:
 

Web框架本质

 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

#!/usr/bin/env python
#coding:utf-8
 
import socket
 
def handle_request(client):
    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n")
    client.send("Hello, Seven")
 
def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8080))
    sock.listen(5)
 
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()
 
if __name__ == '__main__':
    main()
web服务器栗子
运行脚本并在浏览器上访问http://127.0.0.1:8080
注意:对于上述的demo来说,我们没有对请求做分析,对所有的请求都做了相同的处理。
上述分析:
  1、浏览器其实就是一个socket客户端,而web应用其实就是一个socket服务端,并且web应用在服务器上一直在监听某个端口。
  2、当浏览器请求某个web应用时,需要指定服务器的IP(DNS解析)和端口建立一个socket连接。
  3、建立链接后,web应用根据请求的不同,给用户返回相应的数据。
  4、断开socket连接。(之所以说http是短链接,其实就是因为每次请求完成后,服务器就会断开socket链接
栗子分析

    上述通过socket来实现了其本质,而对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。

服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。

       不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。

        对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

 WSGI

WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。

python标准库提供的独立WSGI服务器称为wsgiref。

#!/usr/bin/env python
#coding:utf-8
 
from wsgiref.simple_server import make_server
 
def RunServer(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, web!</h1>'
 
if __name__ == '__main__':
    httpd = make_server('', 8000, RunServer)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()
python标准库提供的独立WSGI服务器称为wsgiref

自定义Web框架

通过python标准库提供的wsgiref模块开发一个自己的Web框架。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
from wsgiref.simple_server import make_server
from jinja2 import Template
 
 
def index():
    # return 'index'
 
    # template = Template('Hello {{ name }}!')
    # result = template.render(name='John Doe')
 
    f = open('index.html')
    result = f.read()
    template = Template(result)
    data = template.render(name='John Doe', user_list=['alex', 'eric'])
    return data.encode('utf-8')
 
 
def login():
    # return 'login'
    f = open('login.html')
    data = f.read()
    return data
 
 
def routers():
 
    urlpatterns = (
        ('/index/', index),
        ('/login/', login),
    )
 
    return urlpatterns
 
 
def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    url = environ['PATH_INFO']
    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == url:
            func = item[1]
            break
    if func:
        return func()
    else:
        return '404 not found'
 
 
if __name__ == '__main__':
    httpd = make_server('', 8000, run_server)
    print "Serving HTTP on port 8000..."
    httpd.serve_forever()
使用开源工具jinja2,遵循其指定语法

如何给用户返回动态内容?

  • 自定义一套特殊的语法,进行替换
  • 使用开源工具jinja2,遵循其指定语法

遵循jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容,对于模板引擎的本质。

1 路由系统

路由系统其实就是 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()
路由系统

2、模板引擎

        Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。

Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% if len(items) > 2 %}。表达语句是使用 {{ 和 }} 包起来的,例如 {{ items[0] }}

控制语句和对应的 Python 语句的格式基本完全相同。我们支持 ifforwhile 和 try,这些语句逻辑结束的位置需要用 {% end %} 做标记。还通过 extends 和 block 语句实现了模板继承。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>{{name}}</h1>

    <ul>
        {% for item in user_list %}
        <li>{{item}}</li>
        {% endfor %}
    </ul>

</body>
</html>

index.html
index.html
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form>
        <input type="text" />
        <input type="text" />
        <input type="submit" />
    </form>
</body>
</html>
login.html

 

#!/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',
}
   
application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)
   
   
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()
index.html_View Code
<!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
#!/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',
}
   
application = tornado.web.Application([
    (r"/index", MainHandler),
], **settings)
   
   
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()
eg:View Code
在模板中默认提供了一些函数、字段、类以供模板使用:

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 的別名
在模板中默认提供了一些函数、字段、类以供模板使用

 

https://github.com/tornadoweb/tornado/blob/master/tornado/template.py


msgstr“”“一个将模板编译成Python代码的简单模板系统。
基本用法看起来像::
    t = template.Template(“<html> {{myvalue}} </ html>”)
    print(t.generate(myvalue =“ XXX ”))
`Loader`是一个从根目录加载模板并缓存的类
编译模板::
    loader = template.Loader(“/ home / btaylor”)
    print(loader.load(“test.html”)。generate(myvalue =“ XXX ”))
我们将所有模板编译为原始Python。错误报告目前是...呃,
有趣。模板的语法::
    ### base.html
    <HTML>
      <HEAD>
        <title> {%block title%}默认标题{%end%} </ title>
      </ HEAD>
      <BODY>
        <UL>
          {%学生在学生%}
            {%block student%}
              <li> {{escape(student.name)}} </ li>
            {% 结束 %}
          {% 结束 %}
        </ UL>
      </ BODY>
    </ HTML>
    ### bold.html
    {%extends“base.html”%}
    {%block title%}更大胆的标题{%end%}
    {%block student%}
      <li> <span style =“bold”> {{escape(student.name)}} </ span> </ li>
    {% 结束 %}
与大多数其他模板系统不同的是,我们不对其进行任何限制
你可以在你的语句中包含表达式。“if”和“for”块得到
完全转换成Python,所以你可以做复杂的表达式,如::
   {如果学生的百分比(如果p.student和p.age> 23的话,则为p)%}
     <li> {{escape(student.name)}} </ li>
   {% 结束 %}
直接翻译到Python意味着您可以将函数应用于表达式
很容易,就像上面例子中的``escape()``函数一样。你可以通过
像任何其他变量一样运行到您的模板中
(在`.RequestHandler`中,覆盖`.RequestHandler.get_template_namespace`)::
   ### Python代码
   def add(x,y):
      返回x + y
   template.execute(添加=添加)
   ###模板
   {{add(1,2)}}
我们提供函数`escape()<.xhtml_escape>`,`.url_escape()`,
`.json_encode()`和`.squeeze()`默认为所有模板。
典型的应用程序不会创建`Template`或`Loader`实例
手,而是使用`〜.RequestHandler.render`和
`〜.RequestHandler.render_string`方法
`tornado.web.RequestHandler`,它自动加载模板
在``template_path```.Application`设置上。
以“_tt_”开头的变量名称由模板保留
系统,不应该被应用程序代码使用。
语法参考
----------------
模板表达式被双花括号包围:``{{...}}``。
内容可能是任何python表达式,这将被转义
到当前的autoescape设置并插入到输出中。其他
模板指令使用``%%}``。
要注释掉某个部分,以便将其从输出中省略,请将其包围
用`{#...#}``。
这些标签可能会被转义为“{{!”,``{%!``和``{#!``
如果你需要在输出中包含一个文字``{{``,``{%``或``##`````
``{%apply * function *%} ... {%end%}``
    在``apply``之间的所有模板代码的输出中应用一个函数
    和``end`` ::
        {%apply linkify%} {{name}}表示:{{message}} {%end%}
    请注意,作为应用程序块的实现细节已经实现
    作为嵌套函数,因此可能会与变量奇怪地交互
    通过“{%set%}”设置,或使用“{%break%}”或“{%continue%}”
    在循环内。
``{%autoescape *函数*%}``
    设置当前文件的自动模式。这不会影响
    其他文件,甚至是由“{%include%}”引用的文件。注意
    自动转义也可以在`.Application`全局配置
    或`Loader`。::
        {%autoescape xhtml_escape%}
        {%autoescape无%}
``{%block * name *%} ... {%end%}``
    表示用于“{%extends%}”的已命名的可替换块。
    父模板中的块将被内容替换
    子模板中的同名块
        <! -  base.html  - >
        <title> {%block title%}默认标题{%end%} </ title>
        <! -  mypage.html  - >
        {%extends“base.html”%}
        {%block title%}我的页面标题{%end%}
``{%comment ...%}``
    将从模板输出中删除的评论。注意
    没有“{%end%}”标签; 评论来自单词``comment``
    到结尾的``````````标记。
`{%extends * filename *%}``
    从另一个模板继承。使用``extends``的模板应该是
    包含一个或多个``block``标记来替换来自父项的内容
    模板。子模板中的任何内容都不包含在“块”中
    标签将被忽略。例如,请参阅“{%block%}”标签。
`{%for * var * in * expr *%} ... {%end%}``
    和python for``语句一样。``{%break%}``和
    可以在循环内使用``%continue%}``。
``{%from * x * import * y *%}``
    和python的``import``语句一样。
``{%if * condition *%} ... {%elif * condition *%} ... {%else%} ... {%end%}`
    条件语句 - 输出条件为的第一部分
    真正。(“elif”和“else”部分是可选的)
``{%import * module *%}``
    和python的``import``语句一样。
``{%include * filename *%}``
    包含另一个模板文件。包含的文件可以看到所有的本地
    变量就好像它被直接复制到“include”的点一样
    指令(“{%autoescape%}”指令是一个例外)。
    或者,可以使用“{%module Template(filename,** kwargs)%}”
    使用独立的名称空间包含另一个模板。
``{%module * expr *%}``
    渲染一个`〜tornado.web.UIModule`。“UIModule”的输出是
    没有逃脱::
        {%module Template(“foo.html”,arg = 42)%}
    ``UIModules``是`tornado.web.RequestHandler`的一个特性
    类(特别是它的“render”方法)并且不起作用
    当模板系统在其他情况下自己使用时。
``{%raw * expr *%}``
    输出给定表达式的结果而不自动转义。
``{%set * x * = * y *%}``
    设置一个局部变量。
`%{%try%} ... {%%%} ... {%else%} ... {%finally%} ... {%end%}`
    和python的``try``语句一样。
``{while while * condition *%} ... {%end%}``
    和python的while语句一样。``{%break%}``和
    可以在循环内使用``%continue%}``。
``%{空白*模式*%}``
    为当前文件的其余部分设置空白模式
    (或者直到下一个`{%whitespace%}`指令)。看到
    `filter_whitespace`为可用的选项。新的龙卷风4.3。
“””

从 __future__  导入 absolute_import,division,print_function

导入日期时间
导入 linecache
导入 os.path
导入 posixpath
导入重新
导入线程

从龙卷风进口逃生
从 tornado.log 导入 app_log
从 tornado.util 导入 ObjectDict,exec_in,unicode_type,PY3

如果 PY3:
    从 io 导入 StringIO
其他:
    从 cStringIO 导入 StringIO

_DEFAULT_AUTOESCAPE  =  “ xhtml_escape ”
_UNSET  =  object()


def  filter_whitespace(mode,text):
    msgstr“” “根据”mode “在”text “中转换空格。”
    可用的模式是:
    *``all``:返回所有未修改的空白。
    *``single``:用一个空白符合连续的空格
      性格,保留换行符。
    *``oneline``:将所有运行的空白符合到一个空格中
      字符,删除过程中的所有换行符。
    .. versionadded :: 4.3
    “””
    如果模式==  '全部':
        返回文本
    elif mode ==  ' single ':
        text = re.sub(r “([ \ t ] +)” ,“  ”,text)
        text = re.sub(r “(\ s * \ n \ s *)”,“ \ n ”,text)
        返回文本
    elif模式==  ' oneline 'return re.sub(r “(\ s +)”,“  ”,text)
    其他:
        引发 异常(“无效的空白模式%s ” %模式)


类 模板(对象):
    “”一个编译好的模板。
    我们从给定的template_string编译成Python。你可以生成
    使用generate()从变量中获取模板。
    “””
    #请注意构造函数的签名不是用提取的
    #车博士因为_UNSET看起来像垃圾。改变时
    #这个签名更新网站/ sphinx / template.rst也是。
    def  __init__(self,template_string,name = “ <string> ”,loader = None,
                 compress_whitespace = _UNSET,autoescape = _UNSET,
                 whitespace = None):
        “”“构建一个模板。
        :arg str template_string:模板文件的内容。
        :arg str name:从中加载模板的文件名
            (用于错误消息)。
        :arg tornado.template.BaseLoader loader:负责这个模板的`〜tornado.template.BaseLoader`,
            用于解析``%include%}``和``{%extend%}``
            指令。
        :arg bool compress_whitespace:自Tornado 4.3以来已弃用。
            等同于“whitespace =”单个“”`如果为true和
            如果为空,则全部为空格。
        :arg str autoescape:模板中函数的名称
            命名空间或“无”来默认禁用转义。
        :arg str whitespace:一个字符串,指定对空白的处理;
            看到`filter_whitespace`选项。
        .. versionchanged :: 4.3
           增加了“whitespace”参数; 不推荐使用``compress_whitespace``。
        “””
        self .name = escape.native_str(name)

        如果 compress_whitespace 是 不是 _UNSET:
            #将不推荐使用的compress_whitespace(bool)转换为空格(str)。
            如果空白是 不 无:
                引发 异常(“不能设置空白和compress_whitespace ”)
            whitespace =  “ single ” 如果 compress_whitespace else  “ all ”
        如果空白是 无:
            如果 loader 和 loader.whitespace:
                whitespace = loader.whitespace
            其他:
                #空格按文件名默认。
                如果 name.endswith(“. html ”)或 name.endswith(“. js ”):
                    whitespace =  “单个”
                其他:
                    whitespace =  “全部”
        #验证空白设置。
        filter_whitespace(空格,' ')

        如果 autoescape 是 不是 _UNSET:
            self .autoescape = autoescape
        elif loader:
            self .autoescape = loader.autoescape
        其他:
            self .autoescape =  _DEFAULT_AUTOESCAPE

        self .namespace = loader.namespace if loader else {}
        reader = _TemplateReader(name,escape.native_str(template_string),
                                 空格)
        self .file = _File(self,_parse(reader,self))
        自 .CODE =  自 ._generate_python(装载机)
        self .loader = loader
        尝试:
            #在python2.5下,这里使用的假文件名必须匹配
            #下面__name__中使用的模块名称。
            #在dont_inherit标志可防止template.py未来进口
            #被应用到生成的代码。
            self .compiled =  compile(
                escape.to_unicode(self .code ),
                “ %S .generated.py ” % 自 .name.replace( ' '' _ '),
                “ exec ”, dont_inherit = True)
        除 例外情况:
            formatted_code = _format_code(self .code).rstrip()
            app_log.error(“ %s code:\ n %s ”,self .name,formatted_code)
            提高

    def  生成(self,** kwargs):
        msgstr“”“用给定的参数生成这个模板。”“”
        namespace = {
            “逃生”:escape.xhtml_escape,
            “ xhtml_escape ”:escape.xhtml_escape,
            “ url_escape ”:escape.url_escape,
            “ json_encode ”:escape.json_encode,
            “挤”:逃避挤压,
            “ linkify ”:escape.linkify,
            “ datetime ”:datetime,
            “ _tt_utf8 ”:escape.utf8,  #供内部使用
            “ _tt_string_types ”:(unicode_type, bytes),
            # __name__和__loader__允许追溯机制,以找到
            #生成的源代码。
            “ __name__ ”: self .name.replace( ''' _ '),
            “ __loader__ ”:ObjectDict( get_source = lambda  名称: self .code),
        }
        namespace.update(self .namespace)
        namespace.update(kwargs)
        exec_in(self .compiled,namespace)
        execute = namespace [ “ _tt_execute ” ]
        #现在清除回溯模块的源数据缓存
        #我们已经生成了一个新的模板(主要是为了这个模块的
        #单元测试,其中不同的测试重用相同的名称)。
        linecache.clearcache()
        返回 execute()

    def  _generate_python(self,loader):
        buffer = StringIO()
        尝试:
            # named_blocks从名字到_NamedBlock对象映射
            named_blocks = {}
            祖先=  自我 ._get_ancestors(加载器)
            ancestors.reverse()
            为祖先在祖先:
                ancestor.find_named_blocks(loader,named_blocks)
            writer = _CodeWriter(buffer,named_blocks,loader,
                                 祖先[ 0 ] .template)
            祖先[ 0 ]。生成(作家)
            return buffer.getvalue()
        最后:
            buffer.close()

    def  _get_ancestors(self,loader):
        ancestors = [ self .file]
        对于大块的 自我 .file.body.chunks:
            如果 isinstance(chunk,_ExtendsBlock):
                如果 不是装载机:
                    引发 ParseError(“ {%extends%}”块发现,但没有“
                                     “模板加载器”)
                template = loader.load(chunk.name,self .name)
                ancestors.extend(template._get_ancestors(装载机))
        归还祖先


class  BaseLoader(object):
    msgstr“”“模板加载器的基类。”
    您必须使用模板加载器来使用模板结构
    “{%extends%}”和“{%include%}”。加载器缓存全部
    第一次加载后的模板。
    “””
    def  __init__(self,autoescape = _DEFAULT_AUTOESCAPE,namespace = None,
                 whitespace = None):
        “”“构建一个模板加载器。
        :arg str autoescape:模板中函数的名称
            命名空间,如“xhtml_escape”或“None”禁用
            自动转义默认情况下。
        :arg dict namespace:要添加到默认模板的字典
            名称空间或“无”。
        :arg str whitespace:指定默认行为的字符串
            模板中的空白 看到`filter_whitespace`选项。
            对于以“.html”和“.js”结尾的文件,默认为“single”
            其他文件的“全部”。
        .. versionchanged :: 4.3
           增加了“空白”参数。
        “””
        self .autoescape = autoescape
        self .namespace = namespace 或 {}
        自我 .whitespace =空白
        self .templates = {}
        # self.lock保护self.templates。这是一个重入锁
        #因为模板可能会通过include或者其他模板加载
        # `扩展`。请注意,由于GIL这个代码将是安全的
        #即使没有锁,但可能会导致浪费工作多倍
        #线程试图同时编译相同的模板。
        self .lock = threading.RLock()

    def  reset(self):
        msgstr“”“重置已编译模板的缓存。”“”
        与 自我 .lock:
            self .templates = {}

    def  resolve_path(self,name,parent_path = None):
        “”“将可能相对路径转换为绝对路径(内部使用)。”“”
        引发 NotImplementedError()

    def  load(self,name,parent_path = None):
        “”“加载模板”“”
        name =  self .resolve_path(name,parent_path = parent_path)
        与 自我 .lock:
            如果名称不 以 自我 .templates:
                self .templates [name] =  self ._create_template(name)
            返回 self .templates [name]

    def  _create_template(self,name):
        引发 NotImplementedError()


class  Loader(BaseLoader):
    msgstr“”“从单个根目录加载的模板加载器。
    “””
    def  __init__(self,root_directory,** kwargs):
        超级(Loader,self)。__init__(** kwargs)
        self .root = os.path.abspath(root_directory)

    def  resolve_path(self,name,parent_path = None):
        如果 PARENT_PATH 和 不 parent_path.startswith( “ < ”)和 \
            不是 parent_path.startswith(“ / ”)和 \
                不是 name.startswith(“ / ”):
            current_path = os.path.join(self .root,parent_path)
            file_dir = os.path.dirname(os.path.abspath(current_path))
            relative_path = os.path.abspath(os.path.join(file_dir,name))
            如果 relative_path.startswith(self .root):
                name = relative_path [ len(self .root)+  1:]
        返回名称

    def  _create_template(self,name):
        path = os.path.join(self .root,name)
        与 开放(路径,“ RB ”)作为 F:
            template = Template(f.read(),name = name,loader = self)
            返回模板


类 DictLoader(BaseLoader):
    msgstr“”“从字典中加载的模板加载器。”“”
    def  __init__(self,dict,** kwargs):
        超级(DictLoader,self)。__init__(** kwargs)
        自我 .dict =  dict

    def  resolve_path(self,name,parent_path = None):
        如果 PARENT_PATH 和 不 parent_path.startswith( “ < ”)和 \
            不是 parent_path.startswith(“ / ”)和 \
                不是 name.startswith(“ / ”):
            file_dir = posixpath.dirname(parent_path)
            name = posixpath.normpath(posixpath.join(file_dir,name))
        返回名称

    def  _create_template(self,name):
        返回模板(self .dict [name],name = name,loader = self)


类 _Node(object):
    def  each_child(self):
        return()

    def  生成(自我,作家):
        引发 NotImplementedError()

    def  find_named_blocks(self,loader,named_blocks):
        对于孩子的 自我 .each_child():
            child.find_named_blocks(loader,named_blocks)


类 _File(_Node):
    def  __init__(self,template,body):
        自 .template =模板
        self .body = body
        self .line =  0

    def  生成(自我,作家):
        writer.write_line(“ def _tt_execute():”,self .line)
        用 writer.indent():
            writer.write_line(“ _tt_buffer = [] ”,self .line)
            writer.write_line(“ _tt_append = _tt_buffer.append ”,self .line)
            self .body.generate(作家)
            write.write_line(“ return _tt_utf8('')。join(_tt_buffer)”,self .line)

    def  each_child(self):
        返回(self .body,)


类 _ChunkList(_Node):
    def  __init__(self,chunk):
        自我。Chunks =大块

    def  生成(自我,作家):
        对于大块的 自我 .chunks:
            chunk.generate(作家)

    def  each_child(self):
        回归 自我 .chunks


类 _NamedBlock(_Node):
    def  __init__(self,name,body,template,line):
        self .name = name
        self .body = body
        自 .template =模板
        自 .line区段=线

    def  each_child(self):
        返回(self .body,)

    def  生成(自我,作家):
        block = writer.named_blocks [ self .name]
        用 writer.include(block.template,self .line):
            block.body.generate(作家)

    def  find_named_blocks(self,loader,named_blocks):
        named_blocks [ self .name] =  self
        _Node.find_named_blocks(self,loader,named_blocks)


类 _ExtendsBlock(_Node):
    def  __init__(self,name):
        self .name = name


类 _IncludeBlock(_Node):
    def  __init__(self,name,reader,line):
        self .name = name
        self .template_name = reader.name
        自 .line区段=线

    def  find_named_blocks(self,loader,named_blocks):
        included = loader.load(self .name,self .template_name)
        included.file.find_named_blocks(loader,named_blocks)

    def  生成(自我,作家):
        included = writer.loader.load(self .name,self .template_name)
        与 writer.include(包括,自我 .line):
            included.file.body.generate(作家)


类 _ApplyBlock(_Node):
    def  __init__(self,method,line,body = None):
        self .method =方法
        自 .line区段=线
        self .body = body

    def  each_child(self):
        返回(self .body,)

    def  生成(自我,作家):
        method_name =  “ _tt_apply %d ” % writer.apply_counter
        writer.apply_counter + =  1
        writer.write_line(“ def %s():” % method_name,self .line)
        用 writer.indent():
            writer.write_line(“ _tt_buffer = [] ”,self .line)
            writer.write_line(“ _tt_append = _tt_buffer.append ”,self .line)
            self .body.generate(作家)
            write.write_line(“ return _tt_utf8('')。join(_tt_buffer)”,self .line)
        writer.write_line(“ _tt_append(_tt_utf8(%s(%s())))” %(
            自我。方法,METHOD_NAME),自 .line区段)


类 _ControlBlock(_Node):
    def  __init__(self,statement,line,body = None):
        self .statement =语句
        自 .line区段=线
        self .body = body

    def  each_child(self):
        返回(self .body,)

    def  生成(自我,作家):
        writer.write_line( “ %S:” % 自 .statement,自 .line区段)
        用 writer.indent():
            self .body.generate(作家)
            #以防万一身体空了
            write.write_line(“ pass ”,self .line)


类 _IntermediateControlBlock(_Node):
    def  __init__(self,statement,line):
        self .statement =语句
        自 .line区段=线

    def  生成(自我,作家):
        #以前的块是空的
        write.write_line(“ pass ”,self .line)
        writer.write_line( “ %S:” % 自 .statement,自 .line区段,writer.indent_size()-  1)


类 _Statement(_Node):
    def  __init__(self,statement,line):
        self .statement =语句
        自 .line区段=线

    def  生成(自我,作家):
        writer.write_line(自 .statement,自 .line区段)


类 _Expression(_Node):
    def  __init__(self,expression,line,raw = False):
        自 .expression =表达
        自 .line区段=线
        自我 .raw =原始

    def  生成(自我,作家):
        writer.write_line( “ _tt_tmp = %S ” % 自 .expression,自 .line区段)
        writer.write_line(“ if isinstance(_tt_tmp,_tt_string_types):”
                          “ _tt_tmp = _tt_utf8(_tt_tmp)”, self .line)
        writer.write_line(“ else:_tt_tmp = _tt_utf8(str(_tt_tmp))”,self .line)
        如果 没有 自我。RAW 和 writer.current_template.autoescape 是 不 无:
            #在python3函数中像xhtml_escape返回unicode,
            #所以我们必须再次转换为utf8。
            writer.write_line(“ _tt_tmp = _tt_utf8(%s(_tt_tmp))” %
                              writer.current_template.autoescape,self .line)
        writer.write_line(“ _tt_append(_tt_tmp)”,self .line)


类 _Module(_Expression):
    def  __init__(self,expression,line):
        超级(_Module,self)。__init__(“ _tt_modules。”  +表达式,行,
                                      raw = True)


类 _Text(_Node):
    def  __init__(self,value,line,whitespace):
        自我。价值=值
        自 .line区段=线
        自我 .whitespace =空白

    def  生成(自我,作家):
        value =  self .value

        #如果需要的话,压缩空格,以避免粗糙的启发式
        #改变预先格式化的空白。
        如果 “ <PRE> ” 未 在值:
            value = filter_whitespace(self .whitespace,value)

        如果价值:
            writer.write_line(' _tt_append(%r)' % escape.utf8(value),self .line)


class  ParseError(Exception):
    “”“引发模板语法错误。
    ``ParseError``实例具有``filename``和``lineno``属性
    指出错误的位置。
    .. versionchanged :: 4.3
       增加了``filename``和``lineno``属性。
    “””
    def  __init__(self,message,filename = None,lineno = 0):
        自我 .message =消息
        #名称“文件名”和“行号”是一致的选择
        #与python SyntaxError。
        self .filename =文件名
        self .lineno = lineno

    def  __str__(self):
        返回 ' %s在%s:%d ' %(self .message,self .filename,self .lineno)


类 _CodeWriter(object):
    def  __init__(self,file,named_blocks,loader,current_template):
        self .file =  文件
        self .named_blocks = named_blocks
        self .loader = loader
        self .current_template = current_template
        self .apply_counter =  0
        self .include_stack = []
        self ._indent =  0

    def  indent_size(self):
        返回 自我 ._indent

    def  indent(self):
        类 压头(物体):
            def  __enter__(_):
                self ._indent + =  1
                回报 自我

            def  __exit__(_,* args):
                assert  self ._indent >  0
                self ._indent -  =  1

        返回压头()

    def  include(self,template,line):
        self .include_stack.append((self .current_template,line))
        self .current_template = template

        类 IncludeTemplate(object):
            def  __enter__(_):
                回报 自我

            def  __exit__(_,* args):
                self .current_template =  self .include_stack.pop()[ 0 ]

        返回 IncludeTemplate()

    def  write_line(self,line,line_number,indent = None):
        如果缩进是 None:
            indent =  self ._indent
        line_comment =  '   #%s:%d ' %(self .current_template.name,line_number)
        如果 自我 .include_stack:
            ancestors = [ “ %s:%d ” %(tmpl.name,lineno)
                         for(tmpl,lineno)in  self .include_stack]
            line_comment + =  '(via %s)'''. join(reversed(ancestors))
        print(“     ”  * indent + line + line_comment,file = self .file)


class  _TemplateReader(object):
    def  __init__(self,name,text,whitespace):
        self .name = name
        self .text = text
        自我 .whitespace =空白
        self .line =  1
        自我 .pos =  0

    def  find(self,needle,start = 0,end = None):
        断言 start > =  0,开始
        pos =  self .pos
        开始+ =正面
        如果结束是 无:
            index =  self .text.find(needle,start)
        其他:
            结束+ = pos
            断言结束> =开始
            index =  self .text.find(needle,start,end)
        如果 index !=  - 1:
            index -  = pos
        回报指数

    def  consume(self,count = None):
        如果 count 是 None:
            count =  len(self .text)-  self .pos
        newpos =  self .pos + count
        自 .line区段+ =  自 .text.count( “ \ n ”,自 .POS,newpos)
        s =  self .text [ self .pos:newpos]
        自我 .pos = newpos
        返回 s

    def  remaining(self):
        return  len(self .text)-  self .pos

    def  __len__(self):
        返回 自我 .remaining()

    def  __getitem__(self,key):
        如果 类型(键)是 切片:
            size =  len(self)
            开始,停止,步骤= key.indices(大小)
            如果启动是 None:
                start =  self .pos
            其他:
                开始+ =  自我 .pos
            如果停止是 不是 无:
                停止+ =  自我 .pos
            return  self .text [ slice(start,stop,step)]
        elif key <  0:
            返回 自我 .text [key]
        其他:
            返回 self .text [ self .pos + key]

    def  __str__(self):
        返回 self .text [ self .pos:]

    def  raise_parse_error(self,msg):
        引发 ParseError(味精,自我。名称,自我。线)


def  _format_code(code):
    lines = code.splitlines()
    format  =  “ %%% d d   %% s \ n ” % len(repr(len(lines)+  1))
    返回 “ ” .join([ 格式 %(i +  1,行)为(i,行)在 枚举(行)])


def  _parse(reader,template,in_block = None,in_loop = None):
    body = _ChunkList([])
    而 真:
        #找到下一个模板指令
        卷曲=  0
        而 真:
            curly = reader.find(“ { ”,curly)
            if curly ==  - 1  or curly +  1  == reader.remaining():
                # EOF
                如果 in_block:
                    reader.raise_parse_error(
                        “缺少%s的%%end%%block ” % in_block)
                body.chunks.append(_Text(reader.consume(),reader.line,
                                         reader.whitespace))
                返回机构
            #如果第一个大括号不是特殊标记的开始,
            #开始从字符开始搜索
            如果读取器[卷曲+  1 ] 未 在(“ { ”,“%”,“#”):
                卷曲+ =  1
                继续
            #当连续超过2个卷曲时,使用
            #最内层的。这在生成语言时很有用
            #像乳胶哪里花括号也是有意义
            如果(卷曲+  2  < reader.remaining()和
                    阅读器[curly +  1 ] ==  ' { ' 和 reader [curly +  2 ] ==  ' { '):
                卷曲+ =  1
                继续
            打破

        #在特殊标记之前附加任何文本
        如果卷曲>  0:
            cons = reader.consume(卷曲)
            body.chunks.append(_Text(cons,reader.line,
                                     reader.whitespace))

        start_brace = reader.consume(2)
        line = reader.line

        #模板指令可能被转义为“{{!” 要么 ”{%!”。
        #在这种情况下输出大括号并使用“!”。
        #这是特别有用的与jQuery模板,
        #也使用双括号。
        如果 reader.remaining()和 reader [ 0 ] ==  “!”:
            reader.consume(1)
            body.chunks.append(_Text(start_brace,line,
                                     reader.whitespace))
            继续

        #评论
        如果 start_brace ==  “ {#”:
            end = reader.find(“#} ”)
            如果结束==  - 1:
                reader.raise_parse_error(“ Missing end comment#} ”)
            contents = reader.consume(end).strip()
            reader.consume(2)
            继续

        #表达
        如果 start_brace ==  “ {{ ”:
            end = reader.find(“ }} ”)
            如果结束==  - 1:
                reader.raise_parse_error(“ Missing end expression }} ”)
            contents = reader.consume(end).strip()
            reader.consume(2)
            如果 不是内容:
                reader.raise_parse_error(“空表达式”)
            body.chunks.append(_Expression(contents,line))
            继续

        #座
        assert start_brace ==  “ {%”,start_brace
        end = reader.find(“%} ”)
        如果结束==  - 1:
            reader.raise_parse_error(“ Missing end block%} ”)
        contents = reader.consume(end).strip()
        reader.consume(2)
        如果 不是内容:
            reader.raise_parse_error(“空块标记({%%})”))

        运算符,空格,后缀= contents.partition(“  ”)
        suffix = suffix.strip()

        #中级(“其他”,“elif”等)块
        intermediate_blocks = {
            “ else ”: set([ “ if ”, “ for ”, “ while ”, “ try ” ]),
            “ elif ”: set([ “ if ” ]),
            “ except ”: set([ “ try ” ]),
            “ finally ”: set([ “ try ” ]),
        }
        allowed_pa​​rents = intermediate_blocks.get(运算符)
        如果 allowed_pa​​rents 是 不 无:
            如果 不是 in_block:
                reader.raise_parse_error( “ %S外%s的块” %
                                         (operator,allowed_pa​​rents))
            如果 in_block 没有 在 allowed_pa​​rents:
                reader.raise_parse_error(
                    “ %s块不能附加到%s块” %
                    (operator,in_block))
            body.chunks.append(_IntermediateControlBlock(contents,line))
            继续

        #结束标记
        elif运算符==  “结束”:
            如果 不是 in_block:
                reader.raise_parse_error(“ Extra {%end%} block ”)
            返回机构

        elif的操作者在(“延伸”,“包括”,“组”,“导入”,“从”,
                          “评论”, “ autoescape ”, “空白”, “生”,
                          “模块”):
            如果 operator ==  “ comment ”:
                继续
            如果 operator ==  “ extends ”:
                suffix = suffix.strip('').strip(” ' “)
                如果 不是后缀:
                    reader.raise_parse_error(“扩展缺少的文件路径”)
                块= _ExtendsBlock(后缀)
            ELIF运营商在(“进口”,“从”):
                如果 不是后缀:
                    reader.raise_parse_error(“导入缺少语句”)
                block = _Statement(contents,line)
            elif运算符==  “包含”:
                suffix = suffix.strip('').strip(” ' “)
                如果 不是后缀:
                    reader.raise_parse_error(“包含缺少的文件路径”)
                block = _IncludeBlock(后缀,阅读器,行)
            elif运算符==  “ set ”:
                如果 不是后缀:
                    reader.raise_parse_error(“设置缺失语句”)
                block = _Statement(后缀,行)
            elif运算符==  “ autoescape ”:
                fn = suffix.strip()
                如果 fn ==  “无”:
                    fn =  无
                template.autoescape = fn
                继续
            elif运算符==  “空白”:
                mode = suffix.strip()
                #验证选定的模式
                filter_whitespace(mode,' ')
                reader.whitespace = mode
                继续
            elif operator ==  “ raw ”:
                block = _Expression(后缀,行,raw = True)
            elif运算符==  “模块”:
                block = _Module(后缀,行)
            body.chunks.append(块)
            继续

        ELIF操作中(“申请”,“块”,“尝试”,“如果”,“对”,“同时”):
            #递归地解析内部体
            如果操作符在(“ for ”,“ while ”)中:
                block_body = _parse(reader,template,operator,operator)
            elif运算符==  “ apply ”:
                #应用创建一个嵌套函数语法所以它不是
                #在循环中。
                block_body = _parse(reader,template,operator,None)
            其他:
                block_body = _parse(reader,template,operator,in_loop)

            如果 operator ==  “ apply ”:
                如果 不是后缀:
                    reader.raise_parse_error(“应用缺少的方法名称”)
                block = _ApplyBlock(后缀,行,block_body)
            elif运算符==  “ block ”:
                如果 不是后缀:
                    reader.raise_parse_error(“ block missing name ”)
                block = _NamedBlock(后缀,block_body,模板,行)
            其他:
                block = _ControlBlock(contents,line,block_body)
            body.chunks.append(块)
            继续

        ELIF运营商在(“破发”,“继续”):
            如果 不是 in_loop:
                reader.raise_parse_error( “ %S外%s的块” %
                                         (operator,set([ “ for ”,“ while ” ])))
            body.chunks.append(_Statement(contents,line))
            继续

        其他:
            reader.raise_parse_error(“未知的操作符:%r ” %操作符)
template 模块 View Code

 

tornado介绍

https://github.com/tornadoweb/tornado

#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = "Flying"
#tornado栗子

from tornado import web,ioloop,httpserver

#逻辑模块
class MainPageHandler(web.RequestHandler):
    def get(self,*args,**kwargs):
        #self.write('welcome to python')
        self.render('index.html')


class CreateHandler(web.RequestHandler):
    def get(self, *args, **kwargs):
        self.render('create.html')

    def post(self, *args, **kwargs):
        web=self.get_argument('web')
        web_tornado=self.get_argument('web_tornado')
        content=self.get_argument('content')
        print web,web_tornado,content

#路由
application = web.Application([
    (r"/index",MainPageHandler),
    (r"/",MainPageHandler),
    (r"/create",CreateHandler),
])

#socket 服务
if __name__ == '__main__':
    http_server = httpserver.HTTPServer(application)
    http_server.listen(9999)
    ioloop.IOLoop.current().start()
tornado web服务器栗子
运行该脚本,依次执行:
      创建一个Application对象,并把一个正则表达式'/'和类名MainHandler传入构造函数:tornado.web.Application(...)  
执行Application对象的listen(...)方法,即:application.listen(9999)
执行IOLoop类的类的 start() 方法,即:tornado.ioloop.IOLoop.instance().start()
     整个过程其实就是在创建一个socket服务端并监听9999端口,当请求到来时,根据请求中的url和请求方式(post、get或put等)来指定相应的类中的方法来处理本次请求,在上述demo中只为url为http://127.0.0.1:9999/index的请求指定了处理类MainHandler。所以,在浏览器上访问:http://127.0.0.1:9999/index,则服务器给浏览器就会返回 Hello,world ,否则返回 404: Not Found(tornado内部定义的值), 即完成一次http请求和响应。

由上述分析,我们将整个Web框架分为两大部分:
待请求阶段,即:创建服务端socket并监听端口
处理请求阶段,即:当有客户端连接时,接受请求,并根据请求的不同做出相应的相应
tornado栗子分析

 

 

tornado请求阶段

tornado程序的源码分析

 

posted on 2017-12-16 14:19  flyoss  阅读(606)  评论(0)    收藏  举报

导航