详解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 文件操作技巧(File operation) 实例代码分析
Aug 11 Python
python使用Tkinter显示网络图片的方法
Apr 24 Python
Python访问纯真IP数据库脚本分享
Jun 29 Python
python的Crypto模块实现AES加密实例代码
Jan 22 Python
浅谈numpy数组中冒号和负号的含义
Apr 18 Python
使用python将时间转换为指定的格式方法
Nov 12 Python
python抓取搜狗微信公众号文章
Apr 01 Python
selenium+python实现自动登陆QQ邮箱并发送邮件功能
Dec 13 Python
python实现堆排序的实例讲解
Feb 21 Python
Python修改列表值问题解决方案
Mar 06 Python
Django中使用Json返回数据的实现方法
Jun 03 Python
Python使用xlrd实现读取合并单元格
Jul 09 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
PHP最常用的2种设计模式工厂模式和单例模式介绍
2012/08/14 PHP
基于php冒泡排序算法的深入理解
2013/06/09 PHP
php写入txt乱码的解决方法
2019/09/17 PHP
用Javascript评估用户输入密码的强度(Knockout版)
2011/11/30 Javascript
javascript 文本框水印/占位符(watermark/placeholder)实现方法
2012/01/15 Javascript
文本域光标操作的jQuery扩展分享
2014/03/10 Javascript
jQuery 过滤方法filter()选择具有特殊属性的元素
2014/06/15 Javascript
js实现特定位取反原理及示例
2014/06/30 Javascript
JavaScript不刷新实现浏览器的前进后退功能
2014/11/05 Javascript
jQuery选择器querySelector的使用指南
2015/01/23 Javascript
jquery获取url参数及url加参数的方法
2015/10/26 Javascript
JavaScript电子时钟倒计时第二款
2016/01/10 Javascript
JavaScript 数组some()和filter()的用法及区别
2016/05/20 Javascript
Java框架SSH结合Easyui控件实现省市县三级联动示例解析
2016/06/12 Javascript
详解Javascript中DOM的范围
2017/02/13 Javascript
Vue非父子组件通信详解
2017/06/12 Javascript
node.js中fs文件系统目录操作与文件信息操作
2018/02/24 Javascript
vue中input的v-model清空操作
2019/09/06 Javascript
python实现在windows服务中新建进程的方法
2015/06/30 Python
Python 多个图同时在不同窗口显示的实现方法
2019/07/07 Python
Python如何读写字节数据
2020/08/05 Python
深入解析HTML5的IndexedDB索引数据库
2015/09/14 HTML / CSS
Mio Skincare中文官网:肌肤和身体护理
2016/10/26 全球购物
新加坡网上花店:FlowerAdvisor新加坡
2018/10/05 全球购物
莫斯科购买书籍网站:Book24
2020/01/12 全球购物
公司年会策划方案
2014/05/17 职场文书
班级心理活动总结
2014/07/04 职场文书
党员学习群众路线教育实践活动对照检查材料
2014/09/23 职场文书
2015年度党员自我评价范文
2015/03/03 职场文书
2015年员工工作表现评语
2015/03/25 职场文书
返乡农民工证明
2015/06/24 职场文书
初中数学课堂教学反思
2016/02/17 职场文书
2019年12月24日平安夜祝福语集锦
2019/12/24 职场文书
SQL实现LeetCode(175.联合两表)
2021/08/04 MySQL
CentOS 7安装mysql5.7使用XtraBackUp备份工具命令详解
2022/04/12 MySQL
vue项目proxyTable配置和部署服务器
2022/04/14 Vue.js