第五篇:白话tornado源码之褪去模板的外衣

author author     2022-08-03     419

关键词:

上一篇《白话tornado源码之请求来了》 介绍了客户端请求在tornado框架中的生命周期,其本质就是利用epoll和socket来获取并处理请求。在上一篇的内容中,我们只是给客户端返回 了简单的字符串,如:“Hello World”,而在实际开发中,需要使用html文件的内容作为模板,然后将被处理后的数据(计算或数据库中的数据)嵌套在模板中,然后将嵌套了数据的 html文件的内容返回给请求者客户端,本篇就来详细的剖析模板处理的整个过程。

概述

技术分享 

上图是返回给用户一个html文件的整个流程,较之前的Demo多了绿色流线的步骤,其实就是把【self.write(‘hello world‘)】变成了【self.render(‘main.html‘)】,对于所有的绿色流线只做了五件事:

  • 使用内置的open函数读取Html文件中的内容
  • 根据模板语言的标签分割Html文件的内容,例如:{{}} 或 {%%}
  • 将分割后的部分数据块格式化成特殊的字符串(表达式)
  • 通过python的内置函数执行字符串表达式,即:将html文件的内容和嵌套的数据整合
  • 将数据返回给请求客户端

所以,如果要返回给客户端对于一个html文件来说,根据上述的5个阶段其内容的变化过程应该是这样:

技术分享 XXXHandler.get
技术分享 1.根据open函数读取html文件内容
技术分享 2.将html内容分块
技术分享 3.将分块的内容进行处理成特殊的特殊的字符串 
技术分享 4.执行字符串表示的函数

在第4步中,执行第3步生成的字符串表示的函数后得到的返回值就是要返回给客户端的响应信息主要内容。

3.13、RequestHandler的render方法

 此段代码主要有三项任务:

  • 获取Html文件内容并把数据(程序数据或框架自带数据)嵌套在内容中的指定标签中本篇主题)
  • 执行ui_modules,再次在html中插入内容,例:head,js文件、js内容、css文件、css内容和body
  • 内部调用客户端socket,将处理请求后的数据返回给请求客户端

对于上述三项任务,第一项是模板语言的重中之重,读取html文件并将数据嵌套到指定标签中,以下的步骤用于剖析整个过程(详情见下文);第二项是对返会给用户内容的补充,也就是在第一项处理完成之后,利用ui_modules再次在html中插入内容(head,js文件、js内容、css文件、css内容和body);第三项是通过socket将内容响应给客户端(见上篇)。

对于ui_modules,每一个ui_module其实就是一个类,一旦注册并 激活了该ui_module,tornado便会自动执行其中的方法:embedded_javascript、javascript_files、 embedded_css、css_files、html_head、html_body和render ,从而实现对html内容的补充。(执行过程见上述代码)

自定义UI Modules

此处是一个完整的 创建 --> 注册 --> 激活 的Demo

目录结构:

  ├── index.py
  ├── static
  └── views
     └── index.html

技术分享 index.py
技术分享 index.html
技术分享 执行结果:

3.13.1~6、RequestHandler的render_string方法

该方法是本篇的重中之重,它负责去处理Html模板并返回最终结果,【概述】中提到的5件事中前四件都是此方法来完成的,即:

  1. 创建Loader对象,并执行load方法
        -- 通过open函数打开html文件并读取内容,并将内容作为参数又创建一个 Template 对象
        -- 当执行Template的 __init__ 方法时,根据模板语言的标签 {{}}、{%%}等分割并html文件,最后生成一个字符串表示的函数
  2. 获取所有要嵌入到html模板中的变量,包括:用户返回和框架默认
  3. 执行Template对象的generate方法
        -- 编译字符串表示的函数,并将用户定义的值和框架默认的值作为全局变量
        -- 执行被编译的函数获取被嵌套了数据的内容,然后将内容返回(用于响应给请求客户端)

注意:详细编译和执行Demo请参见《第四篇:白话tornado源码之褪去模板外衣的前戏 》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class RequestHandler(object):
 
    def render_string(self, template_name, **kwargs):
         
        #获取配置文件中指定的模板文件夹路径,即:template_path = ‘views‘
        template_path = self.get_template_path()
 
        #如果没有配置模板文件的路径,则默认去启动程序所在的目录去找
        if not template_path:
            frame = sys._getframe(0)
            web_file = frame.f_code.co_filename
            while frame.f_code.co_filename == web_file:
                frame = frame.f_back
            template_path = os.path.dirname(frame.f_code.co_filename)
        if not getattr(RequestHandler, "_templates", None):
            RequestHandler._templates = {}
         
        #创建Loader对象,第一次创建后,会将该值保存在RequestHandler的静态字段_template_loaders中
        if template_path not in RequestHandler._templates:
            loader = self.application.settings.get("template_loader") or\
              template.Loader(template_path)
            RequestHandler._templates[template_path] = loader
 
        #执行Loader对象的load方法,该方法内部执行执行Loader的_create_template方法
        #在_create_template方法内部使用open方法会打开html文件并读取html的内容,然后将其作为参数来创建一个Template对象
        #Template的构造方法被执行时,内部解析html文件的内容,并根据内部的 {{}} {%%}标签对内容进行分割,最后生成一个字符串类表示的函数并保存在self.code字段中
        t = RequestHandler._templates[template_path].load(template_name)
         
        #获取所有要嵌入到html中的值和框架默认提供的值
        args = dict(
            handler=self,
            request=self.request,
            current_user=self.current_user,
            locale=self.locale,
            _=self.locale.translate,
            static_url=self.static_url,
            xsrf_form_html=self.xsrf_form_html,
            reverse_url=self.application.reverse_url
        )
        args.update(self.ui)
        args.update(kwargs)
 
        #执行Template的generate方法,编译字符串表示的函数并将namespace中的所有key,value设置成全局变量,然后执行该函数。从而将值嵌套进html并返回。
        return t.generate(**args)
技术分享 Loader.__init__
技术分享 Loader.load
技术分享 Template.__init__
技术分享 Template.generate

其中涉及的类有:

技术分享 _TemplateReader
技术分享 _ChunkList
技术分享 _parse
技术分享 Template._generate_python

so,上述整个过程其实就是将一个html转换成一个函数,并为该函数提供全局变量,然后执行该函数!!

技术分享  技术分享

结束语

上述就是对于模板语言的整个流程,其本质就是处理html文件内容将html文件 内容转换成函数,然后为该函数提供全局变量环境(即:我们想要嵌套进html中的值和框架自带的值),再之后执行该函数从而获取到处理后的结果,再再之后 则执行UI_Modules继续丰富返回结果,例如:添加js文件、添加js内容块、添加css文件、添加css内容块、在body内容第一行插入数据、 在body内容最后一样插入数据,最终,通过soekct客户端对象将处理之后的返回结果(字符串)响应给请求用户。

 

第四篇:白话tornado源码之褪去模板外衣的前戏

...变量本篇的内容从题目中就可以看出来,就是为之后剖析tornado模板做准备,也是由于该知识点使用的巧妙,所有就单独用一篇来介绍了。废话不多说,直接上代码:1234567891011121314#!usr/bin/envpython#coding:utf-8  namespace={‘name... 查看详情

第四篇:白话tornado源码之褪去模板外衣的前戏

...变量本篇的内容从题目中就可以看出来,就是为之后剖析tornado模板做准备,也是由于该知识点使用的巧妙,所有就单独用一篇来介绍了。废话不多说,直接上代码:#!usr/bin/envpython#coding:utf-8namespace={‘name‘:‘wupeiqi‘, 查看详情

第三篇:白话tornado源码之请求来了

上一篇《白话tornado源码之待请求阶段》中介绍了tornado框架在客户端请求之前所做的准备(下图1、2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未执行socket的accept方法,也就是未获取客户端请求信... 查看详情

第二篇:白话tornado源码之待请求阶段

上篇《白话tornado源码之一个脚本引发的血案》用上帝视角多整个框架做了一个概述,同时也看清了web框架的的本质,下面我们从tornado程序的起始来分析其源码。概述上图是tornado程序启动以及接收到客户端请求后的整个过程,对... 查看详情

第一篇:白话tornado源码之一个脚本引发的血案

  1、剖析基于Python的Web框架Tornado的源码  2、为Python开发一个完善的MVC框架    首先将带着大家一起来剖析基于python编写的Web框架tornado,本着易读易懂的目标来写这一系列,寄希让小白也能zeng明白其中的道理,与其说... 查看详情

第一篇:白话tornado源码之一个脚本引发的血案

本系列博文计划:  1、剖析基于Python的Web框架Tornado的源码  2、为Python开发一个完善的MVC框架    首先将带着大家一起来剖析基于python编写的Web框架tornado,本着易读易懂的目标来写这一系列,寄希让小白也能zeng明白其... 查看详情

第三篇:白话tornado源码之请求来了

概述本篇就来详细介绍tornado服务器(socket服务端)是如何接收用户请求数据以及如果根据用户请求的URL处理并返回数据,也就是上图的3系列所有步骤,如上图【start】是一个死循环,其中利用epoll监听服务端socket句柄,一旦客户... 查看详情

第二篇:白话tornado源码之待请求阶段

概述上图是tornado程序启动以及接收到客户端请求后的整个过程,对于整个过程可以分为两大部分:启动程序阶段,又称为待请求阶段(上图1、2所有系列和3.0)接收并处理客户端请求阶段(上图3系列)简而言之:1、在启动程序... 查看详情

前端:redux进阶之褪去react-redux的外衣(代码片段)

一、context实现数据传递  在react中,props和state都可以设置数据。不同的是,props借助组件属性传递数据但不可以渲染组件,它相对来说是“静态的”;state可以监听事件来修改数据并重新渲染组件,它相对来说是“动... 查看详情

第五篇:django的模板层(代码片段)

模板语法符号变量相关模板层之模板传值python基本数据类型全部支持传递给html文件int、?oat、str、list、tuple、dict、set、bool除此之外还可以传入函数,类和对象,其中函数和对象传入过去会自动加括号调用执行。模板语法不支持... 查看详情

构建之法——第五篇

上一周对于需求分析那一模块的内容还存留一点的疑问,经过一周的学习,弄清楚了以下几个方面。   对于软件需求的类型,以及利益相关者,我们根据不同的角度进行了以下的划分,对产品功能性的需求,对产品开... 查看详情

前端工程师技能之photoshop巧用系列第五篇——雪碧图

...描述性图片最终要合并为雪碧图。本文是photoshop巧用系列第五篇——雪碧图 定义  css雪碧图(sprite)是一种网页图片应用处理方式,它允许将一个页面涉及到的所有零星图片都包含到一张大图中。使用雪碧图的处理方式可以... 查看详情

dwr第五篇之文件上传

1. 在第一篇架构基础上进行2. 修改maven依赖1<dependencies>2<dependency>3<groupId>org.directwebremoting</groupId>4  <artifactId>dwr</artifactId>5  <version>3.0.1-RELE 查看详情

javaweb详解(第五篇)之el表达式简介(代码片段)

JavaWeb详解(第五篇)之EL表达式简介1、EL表达式概述1.1、什么是EL表达式  EL是JSP表达式语言,全称是ExpressionLanguage(EL)。EL表达式使用"$"表示,用来更方便的读取对象!1.2、为什么要使用EL表达... 查看详情

cocos2d-x3.2之2048——第五篇

...束了不开心啊,有木有。。!算了,接着发2048吧,这是第五篇了,也非常快了呀,2048系列。立即就要结束了。这篇文章主要讲述:— 查看详情

reactnative安卓开发----第三方框架的引用之react-native-swiper框架实现欢迎页第五篇(代码片段)

#前言今天要介绍的是React-native-Swiper这个RN开源框架,如果你不想用第三方的你也可以自己用viewPagerAndroid去实现,这里先不做介绍了,很简单。想要了解React-native-Swiper源码的童鞋可以在github直接搜索React-native-Swiper。... 查看详情

深入学习jquery选择器系列第五篇——过滤选择器之内容选择器

×目录[1]contains[2]empty[3]parent[4]has[5]not前面的话  本文介绍过滤选择器中的内容选择器。内容选择器的过滤规则主要体现在它所包含的子元素或文本内容上 :contains(text)  :contains(text)选择器选择含有文本内容为‘text‘的... 查看详情

mysql之存储引擎大全-《从0到1-全面深刻理解mysql系列-第五篇》

个人主页:IT学习日记版权:本文由【IT学习日记】原创、在CSDN首发公众号:【IT学习日记】一个只搞干货的公众号如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)、有任何问题欢迎私信,看到会及时回复!文章大纲一、前言二:... 查看详情