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

简介:

上一篇《白话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字段中
         =  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客户端对象将处理之后的返回结果(字符串)响应给请求用户。

 



本文转自武沛齐博客园博客,原文链接:http://www.cnblogs.com/wupeiqi/p/4592066.html,如需转载请自行联系原作者

目录
相关文章
|
7月前
|
Python
小甲鱼 模块与包上 笔记
小甲鱼 模块与包上 笔记
44 0
|
4月前
|
Python
揭秘Python的超能力:魔法方法让你的代码变得无所不能!
【8月更文挑战第22天】Python中的魔法方法,如`__init__`, `__str__`, 和`__add__`, 是特殊的方法名,用于定义对象的行为。例如,`__init__`用于初始化对象属性;`__str__`定义对象的字符串表示,便于打印;`__add__`则允许自定义加法运算。这些方法无需直接调用,而是由Python解释器根据上下文自动调用,让类的行为更加符合Python的风格,从而编写出更优雅且功能丰富的代码。
40 1
|
2月前
|
数据可视化 IDE 程序员
14 款超赞的代码片段生成工具😍(程序员必备)
在本文中,我将介绍 14 款代码片段图片生成器,每款工具都具备独特功能,能够满足不同需求,帮助你将代码转化为精美、易于分享的视觉内容。
123 13
14 款超赞的代码片段生成工具😍(程序员必备)
|
3月前
|
前端开发 JavaScript 持续交付
Web应用开发的方法
Web应用开发的方法
37 1
|
4月前
|
中间件 API 开发者
Bottle框架探秘:如何用几行代码搅动Web开发江湖?
【8月更文挑战第31天】Bottle是一个仅依赖Python标准库的轻量级Web开发微框架,无需额外依赖,简化部署与维护。它以简洁高效著称,适合快速构建Web应用。通过简单的示例即可上手,如用几行代码实现“Hello World”应用。除基础功能外,Bottle还支持模板渲染、会话管理和表单处理等,适用于学习及小型项目,也能在高性能要求的应用中展现价值。无论是新手还是有经验的开发者,Bottle都是高效Web开发的理想选择。
52 1
|
4月前
|
数据库 开发者 数据库管理
【惊艳登场】Bottle框架凭什么成为Web开发新宠儿?一个实战案例告诉你背后的秘密!
【8月更文挑战第31天】Bottle是一个简洁高效的Web框架,适用于构建轻量级应用。本文通过开发一个在线笔记应用,展示了Bottle的核心特性和优势。从环境搭建、路由设置到数据库操作,详细介绍了用户注册、登录、笔记创建及管理等功能的实现过程。通过简洁的语法和灵活的路由机制,Bottle让开发者能快速构建功能完备的应用,提升开发效率。
53 0
|
5月前
|
Python
Python黑魔法揭秘:闭包与装饰器的高级玩法,让你代码飞起来
【7月更文挑战第7天】Python的闭包和装饰器是提升代码效率的神器。闭包是能记住外部作用域变量的内部函数,常用于动态函数创建。示例中,`make_multiplier_of`返回一个保留`n`值的闭包。装饰器则是一个接收函数并返回新函数的函数,用于在不修改原函数情况下添加功能,如日志或性能追踪。`@my_decorator`装饰的`say_hello`函数在执行时会自动加上额外操作。掌握这两者,能让Python代码更优雅、强大。**
36 1
|
7月前
|
Java
从零开始学习 Java:简单易懂的入门指南之反射(三十八)
从零开始学习 Java:简单易懂的入门指南之反射(三十八)
|
移动开发 数据可视化 JavaScript
谈一谈|小白如何使用egret
谈一谈|小白如何使用egret
250 0
|
存储 人工智能 算法
C++ Primer Plus 第6版 读书笔记(7)第 7 章 函数——C++的编程模块
乐趣在于发现。仔细研究,读者将在函数中找到乐趣。C++自带了一个包含函数的大型库(标准 ANSI 库加上多个 C++类),但真正的编程乐趣在于编写自己的函数;另一方面,要提高编程效率,本章和第 8 章介绍如何定义函数、给函数传递信息以及从函数那里获得信息。
170 0
下一篇
DataWorks