context processor学习
来源:互联网 发布:蜜蜡和琥珀哪个贵 知乎 编辑:程序博客网 时间:2024/05/17 21:39
学习nitrate的源码时,在它的template里面看到很多参数能够自动传入模板内,估计是context processor的效果,所以现在来整体学习一下context processor。
在百度上搜索了以下文章,先看一下:http://www.cnblogs.com/btchenguang/archive/2012/09/01/2666763.html
这篇讲的是template的高阶用法,里面就有提到context processor
文章第一节复习了template的用法,没有问题,这个懂,无法就是一些模板函数以及变量的引用,就像文中说的,view.py使用模板的时候,是需要创建类似字典的context对象用作传参,譬如代码里面的done、nowtime都是需要传参的。
复习一下模板语言的用法
{# 模板tag的用法 #}
{% if done %}
Over
{% else %}
wait
{% endif %}
{# 模板变量的用法 #}
Now is {{ nowtime }}
在views.py中使用模板的时候:
1. 通过模板名,获得模板对象
2. 创建context对象,类似字典,用于像模板提供变量实际的值
3. 使用context对象进行模板的渲染,返回的是html网页的内容
文章然后介绍了使用requestcontext对上下文内容进行重用的方法,看了前面的介绍,对重用的概念不理解,继续往下看例子
使用RequestContext对上下文内容进行重用
当渲染一个模板的时候,我们通常使用的是django.template.Context的对象,
这里要介绍另外一个它的子类,django.template.RequestContext,
RequestContext提供了一种把不同的context内容中公共的部分提取出来的方法,
让context的内容重用。例子1. Context版
from django.template import loader, Contextfrom django.http import HttpResponsedef 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))
这个例子能够理解,就是import context对象后,然后定义一个自己的context对象c,然后给c定义一些字典参数,如app、user、message等。然后文中最后一句话说两个view的context对象有些context内容是重复的,也就是说想将所有context内容打包放在一起,然后都传给template,你能用就用,不用也不用管,或者反过来,template在这个池子里面找要用的参数值。
例子2. 下面改写成RequestContext版
from django.template import loader, RequestContextfrom django.http import HttpResponse#使用context processro去提供一些context内容中公共的部分,也就是返回一个字典而已。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') # 创建方式不同,需要提供的参数有三个,request对象,字典类型,processors可选 c = RequestContext(request, {'message': 'I am view 1.'}, processors=[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.'}, processors=[custom_proc]) return HttpResponse(t.render(c))
可以看到所谓的context processors其实就是一个函数,参数为request,
返回一个字典类型。这就是它所做的所有的事。在这里custom_proc返回的
是包含共同的那三个参数的字典RequestContext构造函数中的第三个参数processors是可选的,可以是
多个custom_proc函数的列表或是元组,在这里我们只传递了一个,可以为多个。
赞同文中说的话,这个context processors就是一个函数,接收request,返回公用的字典。而requestcontext就是比context多了一个request和processor,request应该是为了给后面的processors用的,这样processor就可以就根据传参request返回公用字典,requestcontext获得公用字典后,其实和context就没有什么区别了。
结合RequestContext使用render_to_response函数直接返回HttpResponse对象
return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request, processors=[custom_proc]))
以上代码就可以一步到位。
用了这个render_to_response以后,就可以省却了loader.get_template和t.render(c)等等麻烦步骤,而且关键在于最后一个参数,可以通过context_instance来直接引用RequestContext里面返回的公用字典,特别注意,这里的RequestContext干脆没用第二个字典参数,直接用了processors。
但是又引入了另一个问题,在每次使用render_to_response函数时,都要向
RequestContext指定所需要的context processors,因为这个原因,Django又给
我们提供了全局的processors,它默认是被传递给RequestContext对象的,这个设置
对应的是D:\Python27\Lib\site-packages\django\conf\global_setings.py文件
中TEMPLATE_CONTEXT_PROCESSORS属性,这样使用RequestContext的时候,就
不需要每次指定processors了。
是的,每次使用render_to_response函数不单要给给它一个processors,还要import RequestContext,然后又要赋值给contextinstance的确比较麻烦。按文中说的,Django给了一个全局的processors,默认会传给RequestContext,那就省了一些事,起码不用定义processor,然后render_to_response里面的context_instance可以直接等于RequestContext(request)了,省了那么一点事。
然后这个全局的processors应该是在setting里面的,而且默认生成的setting文件里面是没有这货的,必须自己手动加,上Django官网可以找到下面这堆鸡肠,Django1.8之后是这样的:
A tuple of callables that are used to populate the context in RequestContext. These callables take a request object as their argument and return a dictionary of items to be merged into the context.
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ # insert your TEMPLATE_DIRS here ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this # list if you haven't customized them: 'django.contrib.auth.context_processors.auth', 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', ], }, },]
而至于每个processors里面有什么东西,已经这个默认processors怎么被默认传入RequestConext,那就要继续看了。
然后打开第一个processor看看,就是那个auth:
def auth(request): """ Returns context variables required by apps that use Django's authentication system. If there is no 'user' attribute in the request, uses AnonymousUser (from django.contrib.auth). """ if hasattr(request, 'user'): user = request.user else: from django.contrib.auth.models import AnonymousUser user = AnonymousUser() return { 'user': user, 'perms': PermWrapper(user), }
可以看到,获取request参数,判断是否存在user属性(用了hasattr函数),是就将user属性的值赋给user变量,否就import系统的AnonymousUser对象,然后将对象的返回值赋给user。最后返回两个值,一个user,前面已经赋值了;另外一个perms,这东西调用了一个PermWrapper函数,传参是user,这不知道是啥,先查一下。
查了Djangoproject网站,但是查不到,难道不是built-in的方法?再查查模块里面,应该有这个函数。
果然,在上面看到了这段:
class PermWrapper(object): def __init__(self, user): self.user = user def __getitem__(self, app_label): return PermLookupDict(self.user, app_label) def __iter__(self): # I am large, I contain multitudes. raise TypeError("PermWrapper is not iterable.") def __contains__(self, perm_name): """ Lookup by "someapp" or "someapp.someperm" in perms. """ if '.' not in perm_name: # The name refers to module. return bool(self[perm_name]) app_label, perm_name = perm_name.split('.', 1) return self[app_label][perm_name]
分析一下这个类是干嘛的,嗯。。。
先初始化,然后将传参数赋给self.user,ok。
定义一个方法getitem,getitem方法是这样用的,以下两个语句是相等的,用字典式的索引时会自动调用gettiem方法:
PermWrapper['x']PermWrapper.__getitem__('x')
getitem方法获取了传进来的app_label,然后将self.user和app_label作为参数调用了另外一个函数PermLookupDict,这个函数是下面这样的:
class PermLookupDict(object): def __init__(self, user, app_label): self.user, self.app_label = user, app_label def __repr__(self): return str(self.user.get_all_permissions()) def __getitem__(self, perm_name): return self.user.has_perm("%s.%s" % (self.app_label, perm_name)) def __iter__(self): # To fix 'item in perms.someapp' and __getitem__ iteraction we need to # define __iter__. See #18979 for details. raise TypeError("PermLookupDict is not iterable.") def __bool__(self): return self.user.has_module_perms(self.app_label) def __nonzero__(self): # Python 2 compatibility return type(self).__bool__(self)
看着跟PermWrapper有点像,一段一段来分析一下,好烦啊,尼玛。
def __init__(self, user, app_label): self.user, self.app_label = user, app_label
首先还是init,class被instance的时候就会自动运行,没问题的,但是,尼玛,有两个参数哦,一个user,一个app_label哦,分别赋值给了self.user和self.app_label,变成了一个class里面的局部有效的参数,后面的方法就可以直接调用了,ok。
def __repr__(self): return str(self.user.get_all_permissions())
好,然后这货又定义了一个__repr__
方法,__repr__
方法是被repr(instance)的时候就会调用。然后看看它的返回值,user对象的get_all_permissions
方法得到的返回值。但是这个方法我不知道是干嘛的,查这个网页,里面user对象的所有方法都有了:https://docs.djangoproject.com/en/dev/ref/contrib/auth/
然后我们看看方法介绍:
get_all_permissions(obj=None)¶
Returns a set of permission strings that the user has, both through group and user permissions.
If obj is passed in, only returns the permissions for this specific object.
按官方的意思就是返回user对象一系列的权限strings(字符串),包括组权限和用户权限的,一般是不用传参数的,如果你将一个对象作为参数传进去了,那就显示这个指定对象的权限咯。嗯,看是看懂了,不知道效果怎样,后面有机会要试试。
def __getitem__(self, perm_name): return self.user.has_perm("%s.%s" % (self.app_label, perm_name))
还是__getitem__
嘛,就是获取perm_name
然后将init里面获得的self.app_label
和perm_name
一起以一定的字符格式返回去,没啥的。
def __iter__(self): # To fix 'item in perms.someapp' and __getitem__ iteraction we need to # define __iter__. See #18979 for details. raise TypeError("PermLookupDict is not iterable.")
看来哥python没学好啊,尼玛,继续查,不过看样子就是迭代器了。
查了一下,是的,__iter__
就是迭代器啦,iter(class object)的时候就会调用__iter__
方法,一般是返回一个列表(或者tuple、Dict?按官方的话是:the argument must supply its own iterator, or be a sequence),而这里的话直接然后一个Error。
def __bool__(self): return self.user.has_module_perms(self.app_label)
__bool__
求对象的布尔值,一般来说就是被bool(class object)的时候会调用了,然后引进了一个user的新方法has_module_perms()
,官文如下:
>
has_module_perms(package_name)
Returns True if the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always return False.
就是说看user里面有没有这个package(
说完PermLookupDict,回到我们原来的PermWrapper,在定义完gettiem方法以后继续定义了一个iter方法如下:
- context processor学习
- __init__() got an unexpected keyword argument 'context processor'解决方法
- 深入学习Heritrix---解析处理器(Processor)
- Arm 学习笔记 第二章: ARM Processor Fundamentals
- Tomcat学习之Context
- Android Context学习
- Android学习 Context
- Android学习之Context
- android学习3:Context
- Tomcat学习之Context
- Android 学习 context
- Android Context学习
- Context的学习
- Tomcat学习之Context
- Android Context---学习笔记
- Android学习之Context
- react中context学习
- Android学习 ------- Context理解
- Android点击空白区域,隐藏输入法软键盘
- php配置xdebug
- 调用websocket
- SVN环境的搭建
- 机器学习算法(一):聚类算法
- context processor学习
- Java浮点数精度问题
- JAVA基础之内部类总结
- 我和opencv 4 鼠标交互
- 极速 WEB + ORM 框架--JFinal
- snmpwalk命令常用方法总结
- objective-c json 数据组装
- HDU 2084
- 博客声明: