近期因为接口性能问题定位的关系较为深入的了解了Django模板,因此打算写下几篇文章总结记录一下。以下均以Django 1.3.7源码为例来介绍,原来基本是相同的。
一般Django中使用模板时有以下几种方式:
- 通过
direct_to_template
可以直接在url中指定模板,比如
url(r'^test$', direct_to_template, {'template': 'website/test.html'}),
当访问根目录下的test
路径时,将直接使用'website/test.html'
模板来渲染页面
- view中调用
django.shortcuts
的render
方法进行渲染和返回响应结果 - view中调用
django.shortcuts
的render_to_response
方法进行渲染和返回响应结果
render
和render_to_response
的区别在于render
会强制使用django.template.RequestContext
作为模板渲染的参数,而如果工程中使用了模板处理器(settings.TEMPLATE_CONTEXT_PROCESSORS
指定)则必需使用django.template.RequestContext
才能正常加载处理器
上面几种方法最终都会调用django.template.loader.render_to_string
来完成模板的加载,编译和渲染。本次先来看下加载的过程。为了易于理解,只考虑单个模板文件名的情况。
模板加载是在调用render
等方法之后,由django.template.loader.find_template
来完成的。
def find_template(name, dirs=None):
global template_source_loaders
if template_source_loaders is None:
loaders = []
for loader_name in settings.TEMPLATE_LOADERS:
loader = find_template_loader(loader_name)
if loader is not None:
loaders.append(loader)
template_source_loaders = tuple(loaders)
for loader in template_source_loaders:
try:
source, display_name = loader(name, dirs)
return (source, make_origin(display_name, loader, name, dirs))
except TemplateDoesNotExist:
pass
raise TemplateDoesNotExist(name)
这个函数主要完成的就是根据settings.TEMPLATE_LOADERS
中定义的模板加载器依次对模板进行试加载,返回第一个可以加载的模板内容供下一步模板编译来使用。
常用的加载器有一下几种:
-
django.template.loaders.filesystem.Loader
最基础的模板文件加载器,在其内部会调用文件IO接口(open
,read
等)读取模板文件,加载路径为settings.TEMPLATE_DIRS
指定 -
django.template.loaders.cached.Loader
如果担心每次文件读取的IO开销过大,则可以使用cache加载器,所以加载好的模板均以字典形式存在内存中,已经加载的模板不会再次加载。但有两点需要注意- cache loader需要在
settings.TEMPLATE_LOADERS
最前面,否则按照匹配规则,cache会无效 - 每次修改模板时需要重启
Django
才能使其生效
- cache loader需要在
-
django.template.loaders.app_directories.Loader
会检查每个app下面的templates
路径尝试加载模板文件,原理类似于filesystem.Loader
,但是路径不同 -
django.template.loaders.eggs.Loader
类似app_directories
加载器但是尝试从eggs中加载模板文件。Django 1.9之后就废弃了。
模板加载过程就到这里了,后面在总结编译过程。
网友评论