Ticket #5833: custom_filterspecs_plus_fieldless.patch

File custom_filterspecs_plus_fieldless.patch, 10.1 KB (added by korpios, 11 years ago)

Custom FilterSpecs, also allowing fieldless FilterSpecs

  • django/contrib/admin/filterspecs.py

    diff -r 95bbd099704f -r cbc7231501d2 django/contrib/admin/filterspecs.py
    a b  
    1414import datetime
    1515
    1616class FilterSpec(object):
    17     filter_specs = []
    18     def __init__(self, f, request, params, model, model_admin):
    19         self.field = f
     17    def __init__(self, request, params, model, model_admin):
    2018        self.params = params
    21 
    22     def register(cls, test, factory):
    23         cls.filter_specs.append((test, factory))
    24     register = classmethod(register)
    25 
    26     def create(cls, f, request, params, model, model_admin):
    27         for test, factory in cls.filter_specs:
    28             if test(f):
    29                 return factory(f, request, params, model, model_admin)
    30     create = classmethod(create)
    3119
    3220    def has_output(self):
    3321        return True
     
    3624        raise NotImplementedError()
    3725
    3826    def title(self):
    39         return self.field.verbose_name
     27        raise NotImplementedError()
    4028
    4129    def output(self, cl):
    4230        t = []
     
    5139            t.append('</ul>\n\n')
    5240        return mark_safe("".join(t))
    5341
    54 class RelatedFilterSpec(FilterSpec):
    55     def __init__(self, f, request, params, model, model_admin):
    56         super(RelatedFilterSpec, self).__init__(f, request, params, model, model_admin)
    57         if isinstance(f, models.ManyToManyField):
    58             self.lookup_title = f.rel.to._meta.verbose_name
     42class FieldFilterSpec(FilterSpec):
     43    field_filter_specs = []
     44    def __init__(self, request, params, model, model_admin, field):
     45        super(FilterSpec, self).__init__(request, params, model, model_admin)
     46        self.field = field
     47
     48    def register(cls, test, factory):
     49        cls.field_filter_specs.append((test, factory))
     50    register = classmethod(register)
     51
     52    def create(cls, request, params, model, model_admin, field):
     53        for test, factory in cls.field_filter_specs:
     54            if test(field):
     55                return factory(request, params, model, model_admin, field)
     56    create = classmethod(create)
     57
     58    def title(self):
     59        return self.field.verbose_name
     60
     61class RelatedFilterSpec(FieldFilterSpec):
     62    def __init__(self, request, params, model, model_admin, field):
     63        super(RelatedFilterSpec, self).__init__(request, params, model, model_admin, field)
     64        if isinstance(field, models.ManyToManyField):
     65            self.lookup_title = field.rel.to._meta.verbose_name
    5966        else:
    60             self.lookup_title = f.verbose_name
    61         self.lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to._meta.pk.name)
     67            self.lookup_title = field.verbose_name
     68        self.lookup_kwarg = '%s__%s__exact' % (field.name, field.rel.to._meta.pk.name)
    6269        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    63         self.lookup_choices = f.rel.to._default_manager.all()
     70        self.lookup_choices = field.rel.to._default_manager.all()
    6471
    6572    def has_output(self):
    6673        return len(self.lookup_choices) > 1
     
    7784            yield {'selected': self.lookup_val == smart_unicode(pk_val),
    7885                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
    7986                   'display': val}
     87FieldFilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
    8088
    81 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
    82 
    83 class ChoicesFilterSpec(FilterSpec):
    84     def __init__(self, f, request, params, model, model_admin):
    85         super(ChoicesFilterSpec, self).__init__(f, request, params, model, model_admin)
    86         self.lookup_kwarg = '%s__exact' % f.name
     89class ChoicesFilterSpec(FieldFilterSpec):
     90    def __init__(self, request, params, model, model_admin, field):
     91        super(ChoicesFilterSpec, self).__init__(request, params, model, model_admin, field)
     92        self.lookup_kwarg = '%s__exact' % field.name
    8793        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    8894
    8995    def choices(self, cl):
     
    94100            yield {'selected': smart_unicode(k) == self.lookup_val,
    95101                    'query_string': cl.get_query_string({self.lookup_kwarg: k}),
    96102                    'display': v}
     103FieldFilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
    97104
    98 FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
    99 
    100 class DateFieldFilterSpec(FilterSpec):
    101     def __init__(self, f, request, params, model, model_admin):
    102         super(DateFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
     105class DateFieldFilterSpec(FieldFilterSpec):
     106    def __init__(self, request, params, model, model_admin, field):
     107        super(DateFieldFilterSpec, self).__init__(request, params, model, model_admin, field)
    103108
    104109        self.field_generic = '%s__' % self.field.name
    105110
     
    115120                       '%s__month' % self.field.name: str(today.month),
    116121                       '%s__day' % self.field.name: str(today.day)}),
    117122            (_('Past 7 days'), {'%s__gte' % self.field.name: one_week_ago.strftime('%Y-%m-%d'),
    118                              '%s__lte' % f.name: today_str}),
     123                             '%s__lte' % field.name: today_str}),
    119124            (_('This month'), {'%s__year' % self.field.name: str(today.year),
    120                              '%s__month' % f.name: str(today.month)}),
     125                             '%s__month' % field.name: str(today.month)}),
    121126            (_('This year'), {'%s__year' % self.field.name: str(today.year)})
    122127        )
    123128
     
    129134            yield {'selected': self.date_params == param_dict,
    130135                   'query_string': cl.get_query_string(param_dict, [self.field_generic]),
    131136                   'display': title}
     137FieldFilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
    132138
    133 FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
    134 
    135 class BooleanFieldFilterSpec(FilterSpec):
    136     def __init__(self, f, request, params, model, model_admin):
    137         super(BooleanFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
    138         self.lookup_kwarg = '%s__exact' % f.name
    139         self.lookup_kwarg2 = '%s__isnull' % f.name
     139class BooleanFieldFilterSpec(FieldFilterSpec):
     140    def __init__(self, request, params, model, model_admin, field):
     141        super(BooleanFieldFilterSpec, self).__init__(request, params, model, model_admin, field)
     142        self.lookup_kwarg = '%s__exact' % field.name
     143        self.lookup_kwarg2 = '%s__isnull' % field.name
    140144        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    141145        self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None)
    142146
     
    152156            yield {'selected': self.lookup_val2 == 'True',
    153157                   'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
    154158                   'display': _('Unknown')}
    155 
    156 FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
     159FieldFilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
    157160
    158161# This should be registered last, because it's a last resort. For example,
    159162# if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
    160163# more appropriate, and the AllValuesFilterSpec won't get used for it.
    161 class AllValuesFilterSpec(FilterSpec):
    162     def __init__(self, f, request, params, model, model_admin):
    163         super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin)
    164         self.lookup_val = request.GET.get(f.name, None)
    165         self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name)
     164class AllValuesFilterSpec(FieldFilterSpec):
     165    def __init__(self, request, params, model, model_admin, field):
     166        super(AllValuesFilterSpec, self).__init__(request, params, model, model_admin, field)
     167        self.lookup_val = request.GET.get(field.name, None)
     168        self.lookup_choices = model_admin.queryset(request).distinct().order_by(field.name).values(field.name)
    166169
    167170    def title(self):
    168171        return self.field.verbose_name
     
    176179            yield {'selected': self.lookup_val == val,
    177180                   'query_string': cl.get_query_string({self.field.name: val}),
    178181                   'display': val}
    179 FilterSpec.register(lambda f: True, AllValuesFilterSpec)
     182FieldFilterSpec.register(lambda f: True, AllValuesFilterSpec)
     183
  • django/contrib/admin/views/main.py

    diff -r 95bbd099704f -r cbc7231501d2 django/contrib/admin/views/main.py
    a b  
    11from django import template
    2 from django.contrib.admin.filterspecs import FilterSpec
     2from django.contrib.admin.filterspecs import FieldFilterSpec
    33from django.contrib.admin.options import IncorrectLookupParameters
    44from django.contrib.admin.views.decorators import staff_member_required
    55from django.core.exceptions import ObjectDoesNotExist
     
    158158    def get_filters(self, request):
    159159        filter_specs = []
    160160        if self.list_filter and not self.opts.one_to_one_field:
    161             filter_fields = [self.lookup_opts.get_field(field_name) for field_name in self.list_filter]
    162             for f in filter_fields:
    163                 spec = FilterSpec.create(f, request, self.params, self.model, self.model_admin)
     161            for item in self.list_filter:
     162                if callable(item):
     163                    spec = item(
     164                        request, self.params, self.model, self.model_admin
     165                    )
     166                else:
     167                    if type(item) is tuple:
     168                        (name, factory) = item
     169                    else:
     170                        name = item
     171                        factory = FieldFilterSpec.create
     172                    f = self.lookup_opts.get_field(name)
     173                    spec = factory(
     174                        request, self.params, self.model, self.model_admin, f
     175                    )
    164176                if spec and spec.has_output():
    165177                    filter_specs.append(spec)
    166178        return filter_specs, bool(filter_specs)
Back to Top