xadmin的插件机制

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

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

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

@filter_hook

defget_context(self):

"""PRepare the context for templates.

"""self.title = _('%s List') %force_unicode(self.opts.verbose_name)

model_fields = [(f, f.name inself.list_display, self.get_check_field_url(f))

for f in (self.opts.fields + self.get_model_method_fields()) if f.name not inself.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)

returncontext

@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:

returnfunc()

else:

def_inner_method():

fm =filters[token]

fargs =getargspec(fm)[0]

if len(fargs) == 1:

# Only self arg

result =func()

if result isNone:

returnfm()

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)

deffilter_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)

ifself.plugins:

filters = [(getattr(getattr(p, tag), 'priority', 10), getattr(p, tag))

for p in self.plugins ifcallable(getattr(p, tag, None))]

filters = [f for p, f in sorted(filters, key=lambdax:x[0])]

return filter_chain(filters, len(filters) - 1, _inner_method, *args, **kwargs)

else:

return_inner_method()

return method

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航