xadmin的视图方法中如果加了@filter_hook 标记的都可以作为插件的钩子函数。

例如在ListAdminView类中有许多加了上述标记的方法,

    @filter_hook
def get_context(self):
"""
Prepare the context for templates.
"""
self.title = _('%s List') % force_unicode(self.opts.verbose_name) model_fields = [(f, f.name in self.list_display, self.get_check_field_url(f))
for f in (self.opts.fields + self.get_model_method_fields()) if f.name not in self.list_exclude] new_context = {
'module_name': force_unicode(self.opts.verbose_name_plural),
'title': self.title,
'cl': self,
'model_fields': model_fields,
'clean_select_field_url': self.get_query_string(remove=[COL_LIST_VAR]),
'has_add_permission': self.has_add_permission(),
'app_label': self.app_label,
'brand_name': self.opts.verbose_name_plural,
'brand_icon': self.get_model_icon(self.model),
'add_url': self.model_admin_url('add'),
'result_headers': self.result_headers(),
'results': self.results()
}
context = super(ListAdminView, self).get_context()
context.update(new_context)
return context @filter_hook
def get_response(self, context, *args, **kwargs):
pass

在上述代码中,get_context方法被作为了一个插件钩子函数,当调用该方法的时候,会遍历ListAdminView注册的插件寻找插件中与get_context同名的方法,并把get_context

执行后的结果作为第二个参数(第一个参数是self)传给插件的get_context方法,于是我们可以在get_context方法返回结果前对其结果进行一些修改。正是因为如此,插件的同名方法会比视图的方法多一个参数(用于接收上一个方法传来的返回值)。但这不是绝对的。如果被hook的方法没有返回值则插件方法可以不用多设一个参数。

例如,我们想给ListAdminView传给模板的context中增加一个变量(var),我们可以这样定义一个插件:

以下是插件机制实现的原理,其实就是wrap 目标方法,在装饰器中遍历插件形成针对目标方法的插件方法列表,然后在目标方法执行后递归执行。

注意:比较巧妙的是,func if fargs[1] == '__' else func(),也就是说可以根据参数名来决定是把上一结果传过来还是把上一方法传过来,如果是把上一方法传过来

则可以控制方法的执行顺序,可以在上一方法执行前做点改动。

def filter_chain(filters, token, func, *args, **kwargs):
if token == -1:
return func()
else:
def _inner_method():
fm = filters[token]
fargs = getargspec(fm)[0]
if len(fargs) == 1:
# Only self arg
result = func()
if result is None:
return fm()
else:
raise IncorrectPluginArg(u'Plugin filter method need a arg to receive parent method result.')
else:
return fm(func if fargs[1] == '__' else func(), *args, **kwargs)
return filter_chain(filters, token - 1, _inner_method, *args, **kwargs) def filter_hook(func):
tag = func.__name__
func.__doc__ = "``filter_hook``\n\n" + (func.__doc__ or "") @functools.wraps(func)
def method(self, *args, **kwargs): def _inner_method():
return func(self, *args, **kwargs) if self.plugins:
filters = [(getattr(getattr(p, tag), 'priority', 10), getattr(p, tag))
for p in self.plugins if callable(getattr(p, tag, None))]
filters = [f for p, f in sorted(filters, key=lambda x:x[0])]
return filter_chain(filters, len(filters) - 1, _inner_method, *args, **kwargs)
else:
return _inner_method()
return method

xadmin的插件机制的更多相关文章

  1. 【学】jQuery的源码思路6——增加each,animaion,ajax以及插件机制

    each() 插件机制 animation ajax //each() //这里第一个参数指定将this指向每次循环到的那个元素身上,而第三个参数element其实就是this本身所以和第一个参数是一 ...

  2. ImitateLogin新增插件机制以及又一个社交网站的支持

    我的文章里已经多次介绍 imitate-login ,这是我最近一直在维护的一个使用c#模拟社交网站登录的开源项目,现在新增了对插件的支持以及一个新的网站(由于某种原因,会在文章结束部分介绍:而且仅会 ...

  3. Maven生命周期和插件机制

    Maven中的一个非常重要的概念是生命周期和插件,这篇文章重点介绍下Maven的生命周期. Maven的生命周期是抽象的,具体的功能是有具体的插件来完成的,Maven有相当多的功能插件,以至于Mave ...

  4. php中的钩子(hook插件机制)

    对"钩子"这个概念其实不熟悉,最近看到一个php框架中用到这种机制来扩展项目,所以大概来了解下. hook插件机制的基本思想: 在项目代码中,你认为要扩展(暂时不扩展)的地方放置一 ...

  5. winform插件机制学习

    这两天在看自定义控件,原来有太多知识没有掌握.今天看到插件机制,心里突然一亮,这个东西听了不少次,就是不知道是啥回事.这次有幸书里包含一个案例,我就跟着它一步步来.终于知道是什么回事了.这个应该在软件 ...

  6. [转]仿World Wind构造自己的C#版插件框架——WW插件机制精简改造

    很久没自己写东西啦,早该好好总结一下啦!一个大师说过“一个问题不应该被解决两次!”,除了一个好脑筋,再就是要坚持总结. 最近需要搞个系统的插件式框架,我参照World Wind的插件方式构建了个插件框 ...

  7. WordPress 插件机制的简单用法和原理(Hook 钩子)

    WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它. PS:本文只是简单的总结 ...

  8. 微信开发学习日记(八):7步看懂weiphp插件机制,核心目标是响应微信请求

    又经过了几个小时的梳理.回顾,截至目前,终于对weiphp这个框架的机制搞明白了些.想要完全明白,自然还需要大把的时间.第1步:   配置微信公众号,http://weiphp.jiutianniao ...

  9. typecho流程原理和插件机制浅析(第二弹)

    typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...

随机推荐

  1. SQL 中having 和where的区别分析

    在select语句中可以使用groupby子句将行划分成较小的组,然后,使用聚组函数返回每一个组的汇总信息,另外,可以使用having子句限制返回的结果集 在select语句中可以使用groupby子 ...

  2. View,viewgroup,viewstub总结

    :first-child { margin-top: 0; } blockquote > :last-child { margin-bottom: 0; } img { border: 0; m ...

  3. Can't connect to MySQL server on localhost (10061)解决方法

    出现这种错误的原因是由于MySQL的服务被关闭的原因,重新启动一下服务就可以了,启动服务的操作如下: 右键[计算机]-[管理]

  4. Android 获取运营商信息(完整版)-解决高通,MTK等双卡问题

    由于国内的运营商问题,双卡手机获取IMSI号问题要根据厂商API 来实现. 下面我们就来做一套完整的分析运营商获取IMSI号逻辑. 1,首先我们要判断手机的平台. 1.1,判断手机是否MTK平台 1 ...

  5. hadoop错误java.io.IOException Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try

    错误: java.io.IOException: Failed to replace a bad datanode on the existing pipeline due to no more go ...

  6. 3 Ways of JDK Source Code Attachment in Eclipse---reference

    You wanna look at a JVM class while you are coding and you cannot. Here is the solution. First of al ...

  7. 也谈android开发图像压缩

    long long ago,给学院做的一个通讯录App需要有一个上传图像的功能,冥思苦想,绞尽脑汁后来还是没解决(学生时代的事),于是就直接上传原图了,一张图片2M到3M,这样我的应用发布之后,那绝对 ...

  8. JavaScript 开发规范要求详解

    作为一名开发人员(We前端JavaScript开发),不规范的开发不仅使日后代码维护变的困难,同时也不利于团队的合作,通常还会带来代码安全以及执行效率上的问题.本人在开发工作中就曾与不按规范来开发的同 ...

  9. ubuntu 下编译安装 mysql php nginx 及常见错误 (持续添加)

    mysql mysql 可以使用mysql 官方提供的apt源进行安装 参见这里 php 安装前先安装一些常见库 sudo apt-get install libpng16-16 libpng16-d ...

  10. 使用 git 进行项目管理(只管理代码,不管理项目配置)

    使用Git进行项目管理 1. 从服务器pull项目,本地还原工程 从服务器拉取仓库及分支 git clone git@github.com/helloWorld.git git branch -a g ...