最近在学习Django,打算玩玩网页后台方面的东西,由于一直很好奇但却没怎么接触过。Django对我来讲是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,因此你们就凑合着看吧~html
本篇笔记(其实个人全部笔记都是),并不会过于详细的讲解。所以若是有你们看不明白的地方,欢迎在我正版博客下留言,有时间的时候我很愿意来这里与你们探讨问题。(固然,不能是简简单单就能够百度到的问题-.-)django
我所选用的教材是《The Django Book 2.0》,本节是第九章,模板高级进阶。api
本节书中内容仅是参考,更可能是按照文档中内容来介绍。缓存
主要是由于书中版本过期,不少代码刚好是1.8中更新的内容,所以只得直接看文档了。安全
0. 目录app
1. RequestContext函数和context处理器ide
1. RequestContext函数和context处理器
首先,咱们回顾模板的视图函数如何书写:
from django.shortcuts import render_to_response def diary(request): return render_to_response('diary.html', {'name': 'qiqi'})
为了说明方便,咱们同时给出另外一种写法:
from django.http import HttpResponse from django.template import loader, Context def diary(request): t = loader.get_template('diary.html') c = Context({'name': 'qiqi'}) return HttpResponse(t.render(c))
或许仍是有同窗看不懂,那我就再给出第三种最笨的等价写法,你们大可略过直接日后看:
from django.http import HttpResponse from django.template import Template, Context def diary(request): tin = open('./templates/diary.html') html = tin.read() tin.close() inf = {'name': 'qiqi'} t = Template(html) c = Context(inf) return HttpResponse(t.render(c))
在上述代码中,咱们是用Context函数进行渲染的。
而与django.template.Context函数差很少的,还有一个django.template.RequestContext函数,它默认在模板中加了一些变量,好比HttpRequest对象、当前登陆用户的相关信息……
来看下面这段代码:
from django.http import HttpResponse from django.template import loader, Context def view_1(request): # ... t = loader.get_template('template1.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am view 1.' }) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am the second view.' }) return HttpResponse(t.render(c))
其中app、user、ip_address这三个变量,可能须要在不少模板的渲染中重复写入,很麻烦。而利用RequestContext函数,咱们即可以将之简化为这样:
from django.http import HttpResponse from django.template import loader, RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... t = loader.get_template('template1.html') c = RequestContext(request, {'message': 'I am view 1.'}, [custom_proc]) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = RequestContext(request, {'message': 'I am the second view.'}, [custom_proc]) return HttpResponse(t.render(c))
其中,咱们写的函数custom_proc,便称为context处理器。用术语来讲,咱们利用RequestContext函数和context处理器,简化了使用模板的代码。
而在此基础上使用render_to_response,咱们还能够将之简化成:
from django.shortcuts import render_to_response from django.template import RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request, [custom_proc])) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request, [custom_proc]))
此时,仍是有一点美中不足的——渲染语句中,每次都须要手动为processors赋值。
Django提供了对全局context处理器的支持——可让你在全局变量中列出一些context处理器,Django在你每次调用RequestContext函数时都会自动加入这些处理器的。这个全局变量在TEMPLATES参数中能够找到,其默认值是:
# TEMPLATES参数中,'OPTIONS'字典中的,'context_processors'列表 [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ]
这四个值很少说,能够去查书和手册。此时,咱们能够进一步简化代码以下:
from django.shortcuts import render_to_response from django.template import RequestContext def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request)) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request))
至于context处理器,则应当写在单独的一份代码中,推荐命名为context_processors.py。
只要把这份代码放在Python搜索路径中,Django就能够找到。推荐把它放在project或者app的目录下。
# context_processors.py def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] }
最后,修改全局变量便可:
[ 'context_processors.custom_proc', ]
从模板生成html时,总会有一个风险——变量包含了会影响html的字符。
书中举了小例子,这里不加赘述,直接说解决方法:
1. 确保每一个不被信任的变量都用escape过滤器过滤一遍,把潜在的有害html字符转换为无害的。这是初几年Django的处理策略。
2. 利用Django的html自动转义。下面介绍这种方法。
只要你使用Django模板,那么变量标签中的如下五个字符都会被自动转义:
原字符 | 转义结果 |
< | < |
> | > |
' | ' |
" | " |
& | & |
固然,有时候你会本身手动用模板变量写一段html代码,那这时候你就须要关闭自动转义了,关闭方法以下:
1. 变量级别,用safe过滤器: This will not be escaped: {{ data|safe }}
2. 模板级别,用autoescape标签: {% autoescape off %} ... {% endautoescape %}
这个标签有两种状态:off、on。
这个标签是能够嵌套的,例如你能够在一个off的标签内嵌套on的标签。
当你使用模板继承的时候,显而易见,这个标签依旧会持续生效的。
3. 站点级别,这个书中只说有方法,却没写,暂时存疑。
注意:
1. 过滤屡次和过滤一次效果彻底同样。
2. 模板中的字符串常量(例如过滤器中包含的常量)会逃过自动转义,而变量中的字符串则不会。
{{ data|default:"3 < 2" }} {{ data|default:"3 < 2" }} <-- Bad! Don't do this.
存疑:
1. escape过滤器是什么?根据文档中所写,好像是专指autoescape标签?
Engine,简单来讲就是关于模板的一份设置,具体定义这里暂不介绍,你们能够先去文章开头所给的文档中查看,之后有时间会补上。
平时加载模板,使用的就是Django中默认的一个Engine对象,其内容就是我们在settings.py中那个TEMPLATES参数。所以,你用默认的方式加载模板,也就等同于你用Django中这个默认的Engine对象来加载模板。这个对象是: django.template.engines['django']
而若是你想要实例化另外一个Engine对象,则须要用这个定义: django.template.Engine()
Django加载模板的语句有三种:
1. Engine.from_string(template_code)
按照Engine对象的设置,编译所给代码生成模板,返回一个Template对象。
# 方法一,使用默认的Engine from django.template import engines template = engines['django'].from_string(template_code) # 方法二,使用一个空的Engine(没有context_processors之类的东西) from django.template import Engine template = Engine().from_string(template_code)
2. Engine.get_template(template_name)
按照Engine对象的设置,根据所给名称找到模板,在内部进行编译,最后返回一个Template对象。
若是模板不存在,则返回一个TemplateDoesNotExist的异常。
3. Engine.select_template(self, template_name_list)
按照Engine对象的设置,根据所给列表中的名称,顺次寻找模板,把找到的第一个一样处理,返回一个Template对象。
若是全都不存在,则返回一个TemplateDoesNoeExist的异常。
咱们一直说在加载模板,可是TEMPLATES参数中却并无加载器的设置,此时咱们所用的一直是Django中默认的加载器。
下面,咱们就一一介绍Django中的模板加载器:
1. django.template.loaders.filesystem.Loader(默认)
从文件系统中加载模板。
路径:TEMPLATE参数中'DIRS'列表。
2. django.template.loaders.app_directories.Loader
从文件系统中加载模板。
路径:各app,即INSTALLED_APPS参数每一个app目录下的templates文件夹。
开启方式:将TEMPLATES参数中'APP_DIRS'设置为True。
3. django.template.loaders.eggs.Loader
从Python egg中加载模板。
路径:各app。
开启方式:写出相似代码(未经测试,仅供参考)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.eggs.Loader'), ], }, }]
4. django.template.loaders.cached.Loader
加载模板时,第一次调用各加载器加载模板并存入缓存,之后则从缓存中直接加载模板。
路径:取决于调用的各加载器。
注意:实际加载的各模板应该保证其结点(Node)是进程安全(thread-safe)的,详见文档。
开启方式:写出相似代码(源自文档)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ], }, }]
5. django.template.loaders.locmem.Loader
从Python字典中加载模板,经常使用于测试。
存疑:实际效果未测试过,不是很能理解。
开启方式:写出相似代码(源自文档)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.locmem.Loader', { 'index.html': 'content here', }), ], }, }]
实际上,书和文档中还提到了如何写本身的模板、模板中用于debug的两个类、如何写独立模型下的模板……
但因为暂时还用不到,因此先不写了,等之后用到再补充。
至此,“模板高级进阶”内容完结,下一篇是——“模型高级进阶”。