介绍
本文简单探讨一下django模板引擎是如何是实现的。
例如,我们想将如下html中name变量替换
Topics for {{name}}
得到下面的结果
Topics for owen
实现
既然想替换变量,肯定要先识别变量,我们需要一个类Templite来处理html
text = 'Topics for {{name}}
'
context = {'name':'owen'}
初始化参数包括text文本,以及context变量
class Templite(object):
def __init__(self,text,context):
text = text
self.context = context
接下来解析大括号中的内容,首先利用re.split将text按照{{}}进行分割
import re
tokens = re.split(r'({{.*?}})',text)
tokens是下面这样的list
['Topics for ', '{{name}}', '
']
拿到{{name}}了,那怎么替换这个变量呢?
如果接触过namedtuple类,应该知道它的原理是构建python源代码,然后利用exec来执行,这里我们也采用这样的方法
这里用code表示源代码
code = []
定义函数render_context,并加入到code中,函数有一个context参数用来接收变量,code本身也需要一个result用来存储tokens中的变量,这里还需要" "'x4和'\n'*,因为python语法要求缩进和换行
code.extend(['def render_context(context):','\n',' '*4])
code.extend(['result = []','\n',' '*4])
下面只需要判断tokens中的变量然后加入到result当中
for token in tokens:
if token.startswith('{{'):
token = token[2:-2]
code.extend(['%s = context["%s"]'%(token,token),'\n',' '*4])
code.extend(['result.append(%s)'%(token),'\n',' '*4])
else:
code.extend(['result.append("%s")'%(token),'\n',' '*4])
处理完成后,需要增加函数返回值
code.append('return "".join(result)')
再格式化一下code,这样python源代码就完成了
code = ' '.join(code)
下面执行exec,global_namespace变量作为全局命名空间,可以取出render_context函数
global_namespace = {}
exec(code,global_namespace)
self.render_context = global_namespace['render_context']
最后定义一个render函数,获得执行结果
def render(self):
return self.render_context(self.context)
测试
新建Templite对象,执行render函数
tem = Templite(text,context)
print(tem.render())
后续
这里只是实现了模板引擎最简单的功能,条件判断,过滤函数等功能都是在这基础之上实现,可以参考http://aosabook.org/en/500L/a-template-engine.html获得更加详细的说明