xadmin的插件机制

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

 

转载于:https://www.cnblogs.com/zkchen/p/4003611.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值