Ticket #5833: filterspec_with_custom_queryset_against_1_0_2.diff

File filterspec_with_custom_queryset_against_1_0_2.diff, 11.4 KB (added by gerdemb, 10 years ago)
  • contrib/admin/validation.py

     
    66from django.core.exceptions import ImproperlyConfigured
    77from django.db import models
    88from django.forms.models import BaseModelForm, BaseModelFormSet, fields_for_model
     9from django.contrib.admin.filterspecs import FieldFilterSpec
    910from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin
    1011from django.contrib.admin.options import HORIZONTAL, VERTICAL
    1112
     
    5455    # list_filter
    5556    if hasattr(cls, 'list_filter'):
    5657        check_isseq(cls, 'list_filter', cls.list_filter)
    57         for idx, field in enumerate(cls.list_filter):
    58             get_field(cls, model, opts, 'list_filter[%d]' % idx, field)
     58        for idx, item in enumerate(cls.list_filter):
     59            if callable(item):
     60                #TODO find out whether item  is of type FilterSpec
     61                pass
     62            else:
     63                if type(item) is tuple:
     64                    (field, factory) = item
     65                        #TODO find out whether factory is of type (or a descendant of) FieldFilterSpec
     66                        #raise ImproperlyConfigured("'%s.list_filter[%d][1]' is not of type FieldFilterSpec." 
     67                        #    % (cls.__name__, idx))
     68                else:
     69                    field = item
     70                # validate field
     71                get_field(cls, model, opts, 'list_filter[%d]' % idx, field)
    5972
    6073    # list_per_page = 100
    6174    if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int):
  • contrib/admin/filterspecs.py

     
    1414import datetime
    1515
    1616class FilterSpec(object):
    17     filter_specs = []
    18     def __init__(self, f, request, params, model, model_admin):
    19         self.field = f
     17
     18    def __init__(self, request, params, model, model_admin):
    2019        self.params = params
    2120
    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)
    31 
    3221    def has_output(self):
    3322        return True
    3423
     
    3625        raise NotImplementedError()
    3726
    3827    def title(self):
    39         return self.field.verbose_name
     28        raise NotImplementedError()
     29   
     30    def get_query_set(self, cl, qs):
     31        return qs
     32       
    4033
    4134    def output(self, cl):
    4235        t = []
     
    5144            t.append('</ul>\n\n')
    5245        return mark_safe("".join(t))
    5346
    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)
     47class FieldFilterSpec(FilterSpec):
     48    field_filter_specs = []
     49    def __init__(self, request, params, model, model_admin, field):
     50        super(FieldFilterSpec, self).__init__(request, params, model, model_admin)
     51        self.field = field
     52       
     53    def register(cls, test, factory):
     54        cls.field_filter_specs.append((test, factory))
     55    register = classmethod(register)
     56
     57    def title(self):
     58        return self.field.verbose_name
     59   
     60    def create(cls, request, params, model, model_admin, field):
     61        for test, factory in cls.field_filter_specs:
     62            if test(field):
     63                return factory(request, params, model, model_admin, field)
     64    create = classmethod(create)
     65
     66class RelatedFilterSpec(FieldFilterSpec):
     67    def __init__(self, request, params, model, model_admin, f):
     68        super(RelatedFilterSpec, self).__init__(request, params, model, model_admin, f)
    5769        if isinstance(f, models.ManyToManyField):
    5870            self.lookup_title = f.rel.to._meta.verbose_name
    5971        else:
     
    7789                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
    7890                   'display': val}
    7991
    80 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
     92FieldFilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
    8193
    82 class ChoicesFilterSpec(FilterSpec):
    83     def __init__(self, f, request, params, model, model_admin):
    84         super(ChoicesFilterSpec, self).__init__(f, request, params, model, model_admin)
     94class ChoicesFilterSpec(FieldFilterSpec):
     95    def __init__(self, request, params, model, model_admin, f):
     96        super(ChoicesFilterSpec, self).__init__(request, params, model, model_admin, f)
    8597        self.lookup_kwarg = '%s__exact' % f.name
    8698        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    8799
     
    94106                    'query_string': cl.get_query_string({self.lookup_kwarg: k}),
    95107                    'display': v}
    96108
    97 FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
     109FieldFilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
    98110
    99 class DateFieldFilterSpec(FilterSpec):
    100     def __init__(self, f, request, params, model, model_admin):
    101         super(DateFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
     111class DateFieldFilterSpec(FieldFilterSpec):
     112    def __init__(self, request, params, model, model_admin, f):
     113        super(DateFieldFilterSpec, self).__init__(request, params, model, model_admin, f)
    102114
    103115        self.field_generic = '%s__' % self.field.name
    104116
     
    129141                   'query_string': cl.get_query_string(param_dict, [self.field_generic]),
    130142                   'display': title}
    131143
    132 FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
     144FieldFilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
    133145
    134 class BooleanFieldFilterSpec(FilterSpec):
    135     def __init__(self, f, request, params, model, model_admin):
    136         super(BooleanFieldFilterSpec, self).__init__(f, request, params, model, model_admin)
     146class BooleanFieldFilterSpec(FieldFilterSpec):
     147    def __init__(self, request, params, model, model_admin, f):
     148        super(BooleanFieldFilterSpec, self).__init__(request, params, model, model_admin, f)
    137149        self.lookup_kwarg = '%s__exact' % f.name
    138150        self.lookup_kwarg2 = '%s__isnull' % f.name
    139151        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
     
    152164                   'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
    153165                   'display': _('Unknown')}
    154166
    155 FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
     167FieldFilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
    156168
    157169# This should be registered last, because it's a last resort. For example,
    158170# if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
    159171# more appropriate, and the AllValuesFilterSpec won't get used for it.
    160 class AllValuesFilterSpec(FilterSpec):
    161     def __init__(self, f, request, params, model, model_admin):
    162         super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin)
     172class AllValuesFilterSpec(FieldFilterSpec):
     173    def __init__(self, request, params, model, model_admin, f):
     174        super(AllValuesFilterSpec, self).__init__(request, params, model, model_admin, f)
    163175        self.lookup_val = request.GET.get(f.name, None)
    164176        self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name)
    165177
     
    175187            yield {'selected': self.lookup_val == val,
    176188                   'query_string': cl.get_query_string({self.field.name: val}),
    177189                   'display': val}
    178 FilterSpec.register(lambda f: True, AllValuesFilterSpec)
     190FieldFilterSpec.register(lambda f: True, AllValuesFilterSpec)
  • contrib/admin/views/main.py

     
    11from django.contrib.admin.filterspecs import FilterSpec
     2from django.contrib.admin.filterspecs import FieldFilterSpec
    23from django.contrib.admin.options import IncorrectLookupParameters
    34from django.contrib.admin.util import quote
    45from django.core.paginator import Paginator, InvalidPage
     
    6263        if ERROR_FLAG in self.params:
    6364            del self.params[ERROR_FLAG]
    6465
     66        self.filter_specs, self.has_filters = self.get_filters(request)
     67       
    6568        self.order_field, self.order_type = self.get_ordering()
    6669        self.query = request.GET.get(SEARCH_VAR, '')
    6770        self.query_set = self.get_query_set()
    6871        self.get_results(request)
    6972        self.title = (self.is_popup and ugettext('Select %s') % force_unicode(self.opts.verbose_name) or ugettext('Select %s to change') % force_unicode(self.opts.verbose_name))
    70         self.filter_specs, self.has_filters = self.get_filters(request)
     73
    7174        self.pk_attname = self.lookup_opts.pk.attname
    7275
    7376    def get_filters(self, request):
    7477        filter_specs = []
    7578        if self.list_filter:
    76             filter_fields = [self.lookup_opts.get_field(field_name) for field_name in self.list_filter]
    77             for f in filter_fields:
    78                 spec = FilterSpec.create(f, request, self.params, self.model, self.model_admin)
     79            for item in self.list_filter:
     80                if callable(item):
     81                    spec = item(request, self.params, self.model, self.model_admin)
     82                else:
     83                    if type(item) is tuple:
     84                        (name, factory) = item
     85                    else:
     86                        name = item
     87                        factory = FieldFilterSpec.create
     88                    f = self.lookup_opts.get_field(name)
     89                    spec = factory(request, self.params, self.model, self.model_admin, f)
    7990                if spec and spec.has_output():
    8091                    filter_specs.append(spec)
    8192        return filter_specs, bool(filter_specs)
     
    169180
    170181    def get_query_set(self):
    171182        qs = self.root_query_set
     183       
     184        # let every filter do its filtering
     185        for filter_spec in self.filter_specs:
     186            tqs = filter_spec.get_query_set(self, qs)
     187            if tqs != None: qs = tqs
     188       
    172189        lookup_params = self.params.copy() # a dictionary of the query string
    173190        for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR):
    174191            if i in lookup_params:
     
    178195                # 'key' will be used as a keyword argument later, so Python
    179196                # requires it to be a string.
    180197                del lookup_params[key]
    181                 lookup_params[smart_str(key)] = value
     198                key = smart_str(key)
     199                lookup_params[key] = value
    182200
     201            from django.db.models.sql.constants import LOOKUP_SEP
     202            try:
     203                f = self.opts.get_field(key.split(LOOKUP_SEP)[0])
     204            except models.FieldDoesNotExist:
     205                del lookup_params[key]
     206                continue
     207
    183208            # if key ends with __in, split parameter into separate values
    184209            if key.endswith('__in'):
    185210                lookup_params[key] = value.split(',')
Back to Top