国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

xadmin的插件機制

2019-11-14 17:35:08
字體:
來源:轉載
供稿:網友

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

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 资中县| 行唐县| 府谷县| 宣汉县| 乌鲁木齐县| 新巴尔虎左旗| 东明县| 龙岩市| 敖汉旗| 桂阳县| 尚志市| 阳原县| 峡江县| 新兴县| 西峡县| 越西县| 涪陵区| 安西县| 乐清市| 洞头县| 蓝田县| 和平县| 万年县| 昭通市| 牡丹江市| 肥东县| 鲁山县| 全州县| 南城县| 民乐县| 石台县| 淮南市| 五原县| 左权县| 建始县| 密山市| 罗山县| 天全县| 合川市| 合川市| 康定县|