详解Django框架中用context来解析模板的方法


Posted in Python onJuly 20, 2015

你需要一段context来解析模板。 一般情况下,这是一个 django.template.Context 的实例,不过在Django中还可以用一个特殊的子类, django.template.RequestContext ,这个用起来稍微有些不同。 RequestContext 默认地在模板context中加入了一些变量,如 HttpRequest 对象或当前登录用户的相关信息。

当你不想在一系例模板中都明确指定一些相同的变量时,你应该使用 RequestContext 。 例如,考虑这两个视图:

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 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 t.render(c)

(注意,在这些例子中,我们故意 不 使用 render_to_response() 这个快捷方法,而选择手动载入模板,手动构造context对象然后渲染模板。 是为了能够清晰的说明所有步骤。)

每个视图都给模板传入了三个相同的变量:app、user和ip_address。 如果我们把这些冗余去掉会不会更好?

创建 RequestContext 和 context处理器 就是为了解决这个问题。 Context处理器允许你设置一些变量,它们会在每个context中自动被设置好,而不必每次调用 render_to_response() 时都指定。 要点就是,当你渲染模板时,你要用 RequestContext 而不是 Context 。

最直接的做法是用context处理器来创建一些处理器并传递给 RequestContext 。上面的例子可以用context processors改写如下:

from django.template import loader, RequestContext

def custom_proc(request):
  "A context processor that provides 'app', 'user' and 'ip_address'."
  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.'},
      processors=[custom_proc])
  return t.render(c)

def view_2(request):
  # ...
  t = loader.get_template('template2.html')
  c = RequestContext(request, {'message': 'I am the second view.'},
      processors=[custom_proc])
  return t.render(c)

我们来通读一下代码:

    首先,我们定义一个函数 custom_proc 。这是一个context处理器,它接收一个 HttpRequest 对象,然后返回一个字典,这个字典中包含了可以在模板context中使用的变量。 它就做了这么多。

    我们在这两个视图函数中用 RequestContext 代替了 Context 。在context对象的构建上有两个不同点。 一, RequestContext 的第一个参数需要传递一个 HttpRequest 对象,就是传递给视图函数的第一个参数( request )。二, RequestContext 有一个可选的参数 processors ,这是一个包含context处理器函数的列表或者元组。 在这里,我们传递了我们之前定义的处理器函数 curstom_proc 。

    每个视图的context结构里不再包含 app 、 user 、 ip_address 等变量,因为这些由 custom_proc 函数提供了。

    每个视图 仍然 具有很大的灵活性,可以引入我们需要的任何模板变量。 在这个例子中, message 模板变量在每个视图中都不一样。

 为了讲解context处理器底层是如何工作的,在上面的例子中我们没有使用 render_to_response() 。但是建议选择 render_to_response() 作为context的处理器。这就需要用到context_instance参数:

from django.shortcuts import render_to_response
from django.template import RequestContext

def custom_proc(request):
  "A context processor that provides 'app', 'user' and 'ip_address'."
  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, processors=[custom_proc]))

def view_2(request):
  # ...
  return render_to_response('template2.html',
    {'message': 'I am the second view.'},
    context_instance=RequestContext(request, processors=[custom_proc]))

在这,我们将每个视图的模板渲染代码写成了一个单行。

虽然这是一种改进,但是,请考虑一下这段代码的简洁性,我们现在不得不承认的是在 另外 一方面有些过分了。 我们以代码冗余(在 processors 调用中)的代价消除了数据上的冗余(我们的模板变量)。 由于你不得不一直键入 processors ,所以使用context处理器并没有减少太多的输入量。

Django因此提供对 全局 context处理器的支持。 TEMPLATE_CONTEXT_PROCESSORS 指定了哪些context processors总是默认被使用。这样就省去了每次使用 RequestContext 都指定 processors 的麻烦。

默认情况下, TEMPLATE_CONTEXT_PROCESSORS 设置如下:

TEMPLATE_CONTEXT_PROCESSORS = (
  'django.core.context_processors.auth',
  'django.core.context_processors.debug',
  'django.core.context_processors.i18n',
  'django.core.context_processors.media',
)

这个设置项是一个可调用函数的元组,其中的每个函数使用了和上文中我们的 custom_proc 相同的接口,它们以request对象作为参数,返回一个会被合并传给context的字典: 接收一个request对象作为参数,返回一个包含了将被合并到context中的项的字典。

每个处理器将会按照顺序应用。 也就是说如果你在第一个处理器里面向context添加了一个变量,而第二个处理器添加了同样名字的变量,那么第二个将会覆盖第一个。

Django提供了几个简单的context处理器,有些在默认情况下被启用的。

django.core.context_processors.auth

如果 TEMPLATE_CONTEXT_PROCESSORS 包含了这个处理器,那么每个 RequestContext 将包含这些变量:
  •     user :一个 django.contrib.auth.models.User 实例,描述了当前登录用户(或者一个 AnonymousUser 实例,如果客户端没有登录)。
  •     messages :一个当前登录用户的消息列表(字符串)。 在后台,对每一个请求,这个变量都调用 request.user.get_and_delete_messages() 方法。 这个方法收集用户的消息然后把它们从数据库中删除。
  •     perms : django.core.context_processors.PermWrapper 的一个实例,包含了当前登录用户有哪些权限。

关于users、permissions和messages的更多内容请参考第14章。
django.core.context_processors.debug

这个处理器把调试信息发送到模板层。 如果TEMPLATE_CONTEXT_PROCESSORS包含这个处理器,每一个RequestContext将包含这些变量:

  •     debug :你设置的 DEBUG 的值( True 或 False )。你可以在模板里面用这个变量测试是否处在debug模式下。
  •     sql_queries :包含类似于 ``{‘sql': …, ‘time': `` 的字典的一个列表, 记录了这个请求期间的每个SQL查询以及查询所耗费的时间。 这个列表是按照请求顺序进行排列的。
  •     System Message: WARNING/2 (<string>, line 315); backlink
  •     Inline literal start-string without end-string.
  • 由于调试信息比较敏感,所以这个context处理器只有当同时满足下面两个条件的时候才有效:
  •     DEBUG 参数设置为 True 。
  •     请求的ip应该包含在 INTERNAL_IPS 的设置里面。

细心的读者可能会注意到debug模板变量的值永远不可能为False,因为如果DEBUG是False,那么debug模板变量一开始就不会被RequestContext所包含。
django.core.context_processors.i18n

如果这个处理器启用,每个 RequestContext 将包含下面的变量:

  •     LANGUAGES : LANGUAGES 选项的值。
  •     LANGUAGE_CODE :如果 request.LANGUAGE_CODE 存在,就等于它;否则,等同于 LANGUAGE_CODE 设置。

django.core.context_processors.request

如果启用这个处理器,每个 RequestContext 将包含变量 request , 也就是当前的 HttpRequest 对象。 注意这个处理器默认是不启用的,你需要激活它。

如果你发现你的模板需要访问当前的HttpRequest你就需要使用它:

{{ request.REMOTE_ADDR }}

Python 相关文章推荐
使用Python开发windows GUI程序入门实例
Oct 23 Python
详解Python之数据序列化(json、pickle、shelve)
Mar 30 Python
关于python pyqt5安装失败问题的解决方法
Aug 08 Python
Python制作词云的方法
Jan 03 Python
python设置值及NaN值处理方法
Jul 03 Python
python list转矩阵的实例讲解
Aug 04 Python
python获取微信企业号打卡数据并生成windows计划任务
Apr 30 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
Oct 30 Python
python实现百度OCR图片识别过程解析
Jan 17 Python
Vs Code中8个好用的python 扩展插件
Oct 12 Python
手把手教你用Django执行原生SQL的方法
Feb 18 Python
matplotlib阶梯图的实现(step())
Mar 02 Python
Django中URLconf和include()的协同工作方法
Jul 20 #Python
在Python的Django框架中包装视图函数
Jul 20 #Python
Django中URL视图函数的一些高级概念介绍
Jul 20 #Python
Python的Django框架中从url中捕捉文本的方法
Jul 20 #Python
Django框架中处理URLconf中特定的URL的方法
Jul 20 #Python
在Django中创建URLconf相关的通用视图的方法
Jul 20 #Python
python通过socket查询whois的方法
Jul 18 #Python
You might like
DC这些乐高系列动画电影你看过几部?
2020/04/09 欧美动漫
解析centos中Apache、php、mysql 默认安装路径
2013/06/25 PHP
基于php编程规范(详解)
2017/08/17 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
2017/08/28 PHP
JQuery 选择器 xpath 语法应用
2010/05/13 Javascript
Json对象替换字符串占位符实现代码
2010/11/17 Javascript
js中function()使用方法
2013/12/24 Javascript
JS cookie中文乱码解决方法
2014/01/28 Javascript
jQuery简单实现仿京东商城的左侧菜单效果代码
2015/09/09 Javascript
JavaScript、tab切换完整版(自动切换、鼠标移入停止、移开运行)
2016/01/05 Javascript
switch语句的妙用(必看篇)
2016/10/03 Javascript
JS实现颜色梯度与渐变效果完整实例
2016/12/30 Javascript
详解基于webpack2.x的vue2.x的多页面站点
2017/08/21 Javascript
Angularjs添加排序查询功能的实例代码
2017/10/24 Javascript
浅谈webpack打包生成的bundle.js文件过大的问题
2018/02/22 Javascript
jQuery实现的电子时钟效果完整示例
2018/04/28 jQuery
微信小程序点餐系统开发常见问题汇总
2019/08/06 Javascript
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
2019/09/01 Javascript
浅谈vue-router路由切换 组件重用挖下的坑
2019/11/01 Javascript
Element Tooltip 文字提示的使用示例
2020/07/26 Javascript
[43:51]2014 DOTA2国际邀请赛中国区预选赛 Dream Times VS TongFu
2014/05/22 DOTA
用Python的Django框架完成视频处理任务的教程
2015/04/02 Python
浅谈MySQL中的触发器
2015/05/05 Python
深入解析Python设计模式编程中建造者模式的使用
2016/03/02 Python
Python实现选择排序
2017/06/04 Python
Python3 Post登录并且保存cookie登录其他页面的方法
2018/12/28 Python
Python创建数字列表的示例
2019/11/28 Python
Python如何基于selenium实现自动登录博客园
2019/12/16 Python
python使用matplotlib的savefig保存时图片保存不完整的问题
2021/01/08 Python
Zavvi美国:英国娱乐之家
2017/03/19 全球购物
EJB的角色和三个对象
2015/12/31 面试题
幼儿园保育员辞职信
2014/01/12 职场文书
高中数学教学反思
2014/01/30 职场文书
文化产业实施方案
2014/06/07 职场文书
2015年幼儿教师个人工作总结
2015/05/20 职场文书
2016年“抗战胜利纪念日”71周年校园广播稿
2015/12/18 职场文书