cool.admin.filters 源代码

# encoding: utf-8
import random

from django import forms
from django.contrib import admin
from django.contrib.admin import widgets
from django.contrib.admin.utils import get_model_from_relation
from django.contrib.admin.views.main import ERROR_FLAG, PAGE_VAR
from django.forms.widgets import MEDIA_TYPES, Media
from django.utils.http import urlencode
from django.utils.translation import gettext as _

from cool.admin.widgets import (
    CoolAutocompleteSelect, DateRangeFilterWidget, NumberRangeFilterWidget,
)


[文档]class AutocompleteSelect(widgets.AutocompleteSelect): """ 自动提示选择框(支持自定义ajax url) """ def __init__(self, rel, admin_site, attrs=None, choices=(), using=None, custom_url=None): self.custom_url = custom_url super().__init__(rel, admin_site, attrs, choices, using) def get_url(self): return self.custom_url if self.custom_url else super().get_url()
class WidgetFilterMixin: """ 组件筛选器 """ template = 'cool/admin/widget_filter.html' auto_commit = False widget = None widget_attrs = {} def __init__(self, field, request, params, model, model_admin, field_path, *args, **kwargs): super().__init__(field, request, params, model, model_admin, field_path, *args, **kwargs) self.field_path = field_path self.params = dict(request.GET.items()) if PAGE_VAR in self.params: del self.params[PAGE_VAR] if ERROR_FLAG in self.params: del self.params[ERROR_FLAG] self.init_widget(field, request, self.params.copy(), model, model_admin, field_path, *args, **kwargs) if self.widget: self._add_media(model_admin, self.widget) def _add_media(self, model_admin, widget): if not getattr(widget, 'media', None): return model_admin_cls = model_admin.__class__ if not hasattr(model_admin_cls, 'Media'): model_admin_cls.Media = Media def _get_media(obj): return Media(media=getattr(obj, 'Media', None)) media = _get_media(model_admin) + widget.media + _get_media(self) for name in MEDIA_TYPES: setattr(model_admin.Media, name, getattr(media, "_" + name)) def init_widget(self, field, request, params, model, model_admin, field_path, *args, **kwargs): if self.widget: self.widget = self.widget(attrs=self.get_widget_attrs(self.get_param_name(), params, self.widget_attrs)) def get_widget_context(self): if not self.widget: return {} return self.widget.get_context(self.get_param_name(), self.params.get(self.get_param_name()), {}) @classmethod def set_class(cls, widget_context): if 'attrs' not in widget_context: return attrs_class = widget_context['attrs'].get("class", None) if attrs_class: attrs_class += " admin-widget-filter" else: attrs_class = "admin-widget-filter" widget_context['attrs']['class'] = attrs_class @property def widget_render(self): if not self.widget: return '' context = self.get_widget_context() if 'widget' in context: self.set_class(context['widget']) if 'subwidgets' in context['widget'] and len(context['widget']['subwidgets']) == 2: self.set_class(context['widget']['subwidgets'][0]) self.set_class(context['widget']['subwidgets'][1]) return self.widget._render(self.widget.template_name, context, None) def get_param_name(self): raise NotImplementedError def expected_parameters(self): ret = [self.get_param_name(), ] ret.extend(super().expected_parameters()) return ret def get_widget_attrs(self, param_name, params, attrs=None): widget_attrs = attrs.copy() if attrs else {} widget_attrs['data-query-string-value'] = 'data-value-%s' % random.randint(100000000, 999999999) params = params.copy() if params else {} params[param_name] = widget_attrs['data-query-string-value'] widget_attrs['data-query-string'] = "?" + urlencode(params) params.pop(param_name) widget_attrs['data-query-string-all'] = "?" + urlencode(params) return widget_attrs def has_output(self, *args, **kwargs): return True def field_choices(self, *args, **kwargs): return () def choices(self, *args, **kwargs): return () class Media: js = ( 'admin/js/jquery.init.js', 'cool/admin/widget_filter.js' ) class RangeFilterMixin(WidgetFilterMixin): """ 范围筛选器 """ widget_attrs = {'style': 'width:100%'} def get_param1_name(self): return '%s__gte' % self.field_path def get_param2_name(self): return '%s__lte' % self.field_path def expected_parameters(self): return [self.get_param1_name(), self.get_param2_name()] def get_param_name(self): return self.field_path def init_widget(self, field, request, params, model, model_admin, field_path, *args, **kwargs): self.widget = self.widget( attrs=self.widget_attrs, sub1_attrs=self.get_widget_attrs(self.get_param1_name(), params), sub2_attrs=self.get_widget_attrs(self.get_param2_name(), params), ) def get_widget_context(self): return self.widget.get_context( self.get_param_name(), [self.params.get(self.get_param1_name()), self.params.get(self.get_param2_name())], {} )
[文档]class DateRangeFieldFilter(RangeFilterMixin, admin.FieldListFilter): """ 日期筛选器(date字段) """ widget = DateRangeFilterWidget
[文档]class DateTimeRangeFieldFilter(DateRangeFieldFilter): """ 日期筛选器(datetime字段) """ def get_param2_name(self): return '%s__date__lte' % self.field_path
[文档]class NumberRangeFieldFilter(RangeFilterMixin, admin.FieldListFilter): """ 数字筛选器 """ widget = NumberRangeFilterWidget
[文档]class AutocompleteFieldFilter(WidgetFilterMixin, admin.RelatedFieldListFilter): """ 外键制动提示筛选器 """ # def field_choices(self, field, request, model_admin): # return () widget_attrs = {'style': 'width: 100%'} def get_param_name(self): return self.lookup_kwarg def init_widget(self, field, *args, **kwargs): widget = CoolAutocompleteSelect( field, None, attrs=self.get_widget_attrs(self.get_param_name(), self.params, self.widget_attrs) ) other_model = get_model_from_relation(field) field = forms.ModelChoiceField( queryset=other_model.objects, widget=widget, required=False, ) self.widget = field.widget def get_widget_attrs(self, param_name, params, attrs=None): widget_attrs = super().get_widget_attrs(param_name, params, attrs) widget_attrs['data-Placeholder'] = _("Please select %(title)s") % {'title': self.title} return widget_attrs
[文档]class SearchFilter(WidgetFilterMixin, admin.FieldListFilter): """ 精确匹配搜索筛选器 """ widget = widgets.AdminTextInputWidget widget_attrs = {'style': 'width: 100%;box-sizing: border-box;'} def get_param_name(self): return '%s__exact' % self.field_path
[文档]class ISearchFilter(SearchFilter): """ 精确匹配忽略大小写搜索筛选器 """ def get_param_name(self): return '%s__iexact' % self.field_path
[文档]class StartswithFilter(SearchFilter): """ 前缀筛选器 """ def get_param_name(self): return '%s__startswith' % self.field_path
[文档]class IStartswithFilter(SearchFilter): """ 忽略大小写前缀筛选器 """ def get_param_name(self): return '%s__istartswith' % self.field_path
[文档]class ContainsFilter(SearchFilter): """ 模糊匹配筛选器 """ def get_param_name(self): return '%s__contains' % self.field_path
[文档]class IContainsFilter(SearchFilter): """ 忽略大小写模糊匹配筛选器 """ def get_param_name(self): return '%s__icontains' % self.field_path