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

news/2024/7/9 18:02:15 标签: ui, python, epoll

上一篇《白话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源码之褪去模板外衣的前戏 》

python">
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
python keyword">class python plain">RequestHandler( python functions">object python plain">):
 
python spaces">     python keyword">def python plain">render_string( python color1">self python plain">, template_name, python keyword">* python keyword">* python plain">kwargs):
python spaces">         
python spaces">         python comments">#获取配置文件中指定的模板文件夹路径,即:template_path = 'views'
python spaces">         python plain">template_path python keyword">= python color1">self python plain">.get_template_path()
 
python spaces">         python comments">#如果没有配置模板文件的路径,则默认去启动程序所在的目录去找
python spaces">         python keyword">if python keyword">not python plain">template_path:
python spaces">             python plain">frame python keyword">= python plain">sys._getframe( python value">0 python plain">)
python spaces">             python plain">web_file python keyword">= python plain">frame.f_code.co_filename
python spaces">             python keyword">while python plain">frame.f_code.co_filename python keyword">= python keyword">= python plain">web_file:
python spaces">                 python plain">frame python keyword">= python plain">frame.f_back
python spaces">             python plain">template_path python keyword">= python plain">os.path.dirname(frame.f_code.co_filename)
python spaces">         python keyword">if python keyword">not python functions">getattr python plain">(RequestHandler, python string">"_templates" python plain">, python color1">None python plain">):
python spaces">             python plain">RequestHandler._templates python keyword">= python plain">{}
python spaces">         
python spaces">         python comments">#创建Loader对象,第一次创建后,会将该值保存在RequestHandler的静态字段_template_loaders中
python spaces">         python keyword">if python plain">template_path python keyword">not python keyword">in python plain">RequestHandler._templates:
python spaces">             python plain">loader python keyword">= python color1">self python plain">.application.settings.get( python string">"template_loader" python plain">) python keyword">or python plain">\
python spaces">               python plain">template.Loader(template_path)
python spaces">             python plain">RequestHandler._templates[template_path] python keyword">= python plain">loader
 
python spaces">         python comments">#执行Loader对象的load方法,该方法内部执行执行Loader的_create_template方法
python spaces">         python comments">#在_create_template方法内部使用open方法会打开html文件并读取html的内容,然后将其作为参数来创建一个Template对象
python spaces">         python comments">#Template的构造方法被执行时,内部解析html文件的内容,并根据内部的 {{}} {%%}标签对内容进行分割,最后生成一个字符串类表示的函数并保存在self.code字段中
python spaces">         python plain">t python keyword">= python plain">RequestHandler._templates[template_path].load(template_name)
python spaces">         
python spaces">         python comments">#获取所有要嵌入到html中的值和框架默认提供的值
python spaces">         python plain">args python keyword">= python functions">dict python plain">(
python spaces">             python plain">handler python keyword">= python color1">self python plain">,
python spaces">             python plain">request python keyword">= python color1">self python plain">.request,
python spaces">             python plain">current_user python keyword">= python color1">self python plain">.current_user,
python spaces">             python plain">locale python keyword">= python color1">self python plain">.locale,
python spaces">             python plain">_ python keyword">= python color1">self python plain">.locale.translate,
python spaces">             python plain">static_url python keyword">= python color1">self python plain">.static_url,
python spaces">             python plain">xsrf_form_html python keyword">= python color1">self python plain">.xsrf_form_html,
python spaces">             python plain">reverse_url python keyword">= python color1">self python plain">.application.reverse_url
python spaces">         python plain">)
python spaces">         python plain">args.update( python color1">self python plain">.ui)
python spaces">         python plain">args.update(kwargs)
 
python spaces">         python comments">#执行Template的generate方法,编译字符串表示的函数并将namespace中的所有key,value设置成全局变量,然后执行该函数。从而将值嵌套进html并返回。
python spaces">         python keyword">return python plain">t.generate( python keyword">* python keyword">* python plain">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客户端对象将处理之后的返回结果(字符串)响应给请求用户。

 

转载于:https://www.cnblogs.com/maozhr/p/5840692.html


http://www.niftyadmin.cn/n/1065865.html

相关文章

经典算法排序——希尔排序

希尔排序(Shell Sort)又称为缩小增量排序,输入插入排序算法,是对直接排序算法的一种改进。本文介绍希尔排序算法。 对于插入排序算法来说,如果原来的数据就是有序的,那么数据就不需要移动,而插入…

datepicker 时间戳转换问题

js时间戳是以毫秒来计算的,php时间戳是以秒来计算的,所以js直接得到的时间戳要转换成时间要先除以1000。 时间 2016-09-10 和 2016-9-10 转换成时间戳是不一样的 前者是1473465600而后者是1473436800,把前者的时间戳再转换为时间为 2016/9/10…

配置python环境变量(转)

默认情况下,在windows下安装python之后,系统并不会自动添加相应的环境变量。此时不能在命令行直接使用python命令。1.首先需要在系统中注册python环境变量:假设python的安装路径为c:\python2.5,打开“我的电脑->属性->高级-…

Codeforces Round #187 (Div. 2) 只水果两题。。。

再一次证明我就是水水题的水果,今晚的cf就水了前两题,然后就束手无策了。。。 但是我还是厚脸皮的贴出前两题代码。。。 明天去找大神博客膜拜后面几题吧。。。 A 水!题目看了挺长时间,一开始还以为是并查集,想了15分钟…

下一个时代,对话即平台 —— 开始使用Bot Framework和Cognitive Service来打造你的智能对话服务...

在16年3月30号微软的全球开发者大会Build上发布了Bot Framework,微软认为下一个big thing是Conversation as a Platform,简称CaaP,中文应该叫做"对话即平台"。在我们的下个时代,我们将会处在对话即平台的时代&#xff0…

Linux Apache开启gzip压缩提高网页下载速度

为了提高网页浏览速度,我们可以在服务器的apache开启gzip压缩功能,这样压缩使网页更小,自然下载需要的时间就更少了,用户体验更佳。下面来介绍如何开启这个功能。1、首先得确认apache是否已经加载了mod_deflate模块。 httpd -M如何…

Controller简介

Controller控制器,是MVC中的部分C,为什么是部分呢?因为此处的控制器主要负责功能处理部分: 1、收集、验证请求参数并绑定到命令对象; 2、将命令对象交给业务对象,由业务对象处理并返回模型数据;…

超级阶梯 杭电2041

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? Input输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M&…