Ticket #5833: 5833-against-9836-new-proper.patch
File 5833-against-9836-new-proper.patch, 14.3 KB (added by , 16 years ago) |
---|
-
django/contrib/admin/validation.py
8 8 from django.forms.models import BaseModelForm, BaseModelFormSet, fields_for_model 9 9 from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin 10 10 from django.contrib.admin.options import HORIZONTAL, VERTICAL 11 from django.contrib.admin.filterspecs import FilterSpec, FieldFilterSpec 11 12 12 13 __all__ = ['validate'] 13 14 … … 50 51 fetch_attr(cls, model, opts, 'list_display_links[%d]' % idx, field) 51 52 if field not in cls.list_display: 52 53 raise ImproperlyConfigured("'%s.list_display_links[%d]'" 53 " refers to '%s' which is not defined in 'list_display'."54 " refers to '%s' which is not defined in 'list_display'." 54 55 % (cls.__name__, idx, field)) 55 56 56 57 # list_filter 57 58 if hasattr(cls, 'list_filter'): 58 59 check_isseq(cls, 'list_filter', cls.list_filter) 59 for idx, field in enumerate(cls.list_filter): 60 get_field(cls, model, opts, 'list_filter[%d]' % idx, field) 60 for idx, item in enumerate(cls.list_filter): 61 if callable(item): 62 # Make sure the item is not FieldFilterSpec or a subclass thereof 63 # since it has a different __init__ signature, which leads to 64 # strange exceptions if not caught here 65 if not issubclass(item, FilterSpec) or issubclass(item, FieldFilterSpec): 66 raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s' which is not of type FilterSpec." 67 % (cls.__name__, idx, item)) 68 else: 69 try: 70 field_name, factory = item 71 except (TypeError, ValueError): 72 field_name = item 73 else: 74 if not issubclass(factory, FieldFilterSpec): 75 raise ImproperlyConfigured("'%s.list_filter[%d][1]'" 76 " refers to '%s' which is not of type FieldFilterSpec." 77 % (cls.__name__, idx, factory.__name__)) 78 # Validate field 79 get_field(cls, model, opts, 'list_filter[%d]' % idx, field) 61 80 62 81 # list_per_page = 100 63 82 if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int): -
django/contrib/admin/__init__.py
1 1 from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 2 2 from django.contrib.admin.options import StackedInline, TabularInline 3 3 from django.contrib.admin.sites import AdminSite, site 4 from django.contrib.admin.filterspecs import FilterSpec, FieldFilterSpec 4 5 5 6 # A flag to tell us if autodiscover is running. autodiscover will set this to 6 7 # True while running, and False when it finishes. -
django/contrib/admin/filterspecs.py
14 14 import datetime 15 15 16 16 class 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): 20 18 self.params = params 21 19 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 32 20 def has_output(self): 33 21 return True 34 22 35 23 def choices(self, cl): 36 24 raise NotImplementedError() 37 25 38 26 def title(self): 39 return self.field.verbose_name 27 raise NotImplementedError() 28 29 def get_query_set(self, cl, qs): 30 return False 31 32 def consumed_params(self): 33 """ 34 Return a list of parameters to consume from the change list querystring. 35 36 Override this for non-field based FilterSpecs subclasses in order 37 to consume custom GET parameters, as any GET parameters that are not 38 consumed and are not a field name raises an exception. 39 """ 40 return [] 40 41 41 42 def output(self, cl): 42 43 t = [] … … 50 51 choice['display'])) 51 52 t.append('</ul>\n\n') 52 53 return mark_safe("".join(t)) 54 55 class FieldFilterSpec(FilterSpec): 56 field_filter_specs = [] 57 _high_priority_index = 0 58 59 def __init__(self, request, params, model, model_admin, f): 60 super(FieldFilterSpec, self).__init__(request, params, model, model_admin) 61 self.field = f 62 63 def title(self): 64 return self.field.verbose_name 65 66 def register(cls, test, factory, high_priority=True): 67 if high_priority: 68 cls.field_filter_specs.insert(cls._high_priority_index, (test, factory)) 69 cls._high_priority_index += 1 70 else: 71 cls.field_filter_specs.append((test, factory)) 72 register = classmethod(register) 73 74 def create(cls, request, params, model, model_admin, f): 75 for test, factory in cls.field_filter_specs: 76 if test(f): 77 return factory(request, params, model, model_admin, f) 78 create = classmethod(create) 53 79 54 class RelatedFilterSpec(Fi lterSpec):55 def __init__(self, f, request, params, model, model_admin):56 super(RelatedFilterSpec, self).__init__( f, request, params, model, model_admin)80 class RelatedFilterSpec(FieldFilterSpec): 81 def __init__(self, request, params, model, model_admin, f): 82 super(RelatedFilterSpec, self).__init__(request, params, model, model_admin, f) 57 83 if isinstance(f, models.ManyToManyField): 58 84 self.lookup_title = f.rel.to._meta.verbose_name 59 85 else: … … 77 103 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}), 78 104 'display': val} 79 105 80 Fi lterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)106 FieldFilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec, False) 81 107 82 class ChoicesFilterSpec(Fi lterSpec):83 def __init__(self, f, request, params, model, model_admin):84 super(ChoicesFilterSpec, self).__init__( f, request, params, model, model_admin)108 class ChoicesFilterSpec(FieldFilterSpec): 109 def __init__(self, request, params, model, model_admin, f): 110 super(ChoicesFilterSpec, self).__init__(request, params, model, model_admin, f) 85 111 self.lookup_kwarg = '%s__exact' % f.name 86 112 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 87 113 … … 94 120 'query_string': cl.get_query_string({self.lookup_kwarg: k}), 95 121 'display': v} 96 122 97 Fi lterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)123 FieldFilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec, False) 98 124 99 class DateFieldFilterSpec(Fi lterSpec):100 def __init__(self, f, request, params, model, model_admin):101 super(DateFieldFilterSpec, self).__init__( f, request, params, model, model_admin)125 class DateFieldFilterSpec(FieldFilterSpec): 126 def __init__(self, request, params, model, model_admin, f): 127 super(DateFieldFilterSpec, self).__init__(request, params, model, model_admin, f) 102 128 103 129 self.field_generic = '%s__' % self.field.name 104 130 … … 120 146 (_('This year'), {'%s__year' % self.field.name: str(today.year)}) 121 147 ) 122 148 123 def title(self):124 return self.field.verbose_name125 126 149 def choices(self, cl): 127 150 for title, param_dict in self.links: 128 151 yield {'selected': self.date_params == param_dict, 129 152 'query_string': cl.get_query_string(param_dict, [self.field_generic]), 130 153 'display': title} 131 154 132 Fi lterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)155 FieldFilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec, False) 133 156 134 class BooleanFieldFilterSpec(Fi lterSpec):135 def __init__(self, f, request, params, model, model_admin):136 super(BooleanFieldFilterSpec, self).__init__( f, request, params, model, model_admin)157 class BooleanFieldFilterSpec(FieldFilterSpec): 158 def __init__(self, request, params, model, model_admin, f): 159 super(BooleanFieldFilterSpec, self).__init__(request, params, model, model_admin, f) 137 160 self.lookup_kwarg = '%s__exact' % f.name 138 161 self.lookup_kwarg2 = '%s__isnull' % f.name 139 162 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 140 163 self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None) 141 164 142 def title(self):143 return self.field.verbose_name144 145 165 def choices(self, cl): 146 166 for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')): 147 167 yield {'selected': self.lookup_val == v and not self.lookup_val2, … … 152 172 'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]), 153 173 'display': _('Unknown')} 154 174 155 Fi lterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)175 FieldFilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec, False) 156 176 157 177 # This should be registered last, because it's a last resort. For example, 158 178 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much 159 179 # more appropriate, and the AllValuesFilterSpec won't get used for it. 160 class AllValuesFilterSpec(Fi lterSpec):161 def __init__(self, f, request, params, model, model_admin):162 super(AllValuesFilterSpec, self).__init__( f, request, params, model, model_admin)180 class AllValuesFilterSpec(FieldFilterSpec): 181 def __init__(self, request, params, model, model_admin, f): 182 super(AllValuesFilterSpec, self).__init__(request, params, model, model_admin, f) 163 183 self.lookup_val = request.GET.get(f.name, None) 164 184 self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name) 165 185 166 def title(self):167 return self.field.verbose_name168 169 186 def choices(self, cl): 170 187 yield {'selected': self.lookup_val is None, 171 188 'query_string': cl.get_query_string({}, [self.field.name]), … … 175 192 yield {'selected': self.lookup_val == val, 176 193 'query_string': cl.get_query_string({self.field.name: val}), 177 194 'display': val} 178 Fi lterSpec.register(lambda f: True, AllValuesFilterSpec)195 FieldFilterSpec.register(lambda f: True, AllValuesFilterSpec, False) -
django/contrib/admin/views/main.py
1 from django.contrib.admin.filterspecs import FilterSpec 1 from django.contrib.admin.filterspecs import FilterSpec, FieldFilterSpec 2 2 from django.contrib.admin.options import IncorrectLookupParameters 3 3 from django.contrib.admin.util import quote 4 4 from django.core.paginator import Paginator, InvalidPage … … 62 62 if ERROR_FLAG in self.params: 63 63 del self.params[ERROR_FLAG] 64 64 65 self.filter_specs, self.has_filters = self.get_filters(request) 65 66 self.order_field, self.order_type = self.get_ordering() 66 67 self.query = request.GET.get(SEARCH_VAR, '') 67 68 self.query_set = self.get_query_set() 68 69 self.get_results(request) 69 70 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)71 71 self.pk_attname = self.lookup_opts.pk.attname 72 72 73 73 def get_filters(self, request): 74 74 filter_specs = [] 75 75 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) 76 for item in self.list_filter: 77 if callable(item): 78 spec = item(request, self.params, self.model, self.model_admin) 79 else: 80 try: 81 field_name, factory = item 82 except (TypeError, ValueError): 83 field_name, factory = item, FieldFilterSpec.create 84 field = self.lookup_opts.get_field(field_name) 85 spec = factory(request, self.params, self.model, 86 self.model_admin, field) 79 87 if spec and spec.has_output(): 80 88 filter_specs.append(spec) 81 89 return filter_specs, bool(filter_specs) … … 183 191 # if key ends with __in, split parameter into separate values 184 192 if key.endswith('__in'): 185 193 lookup_params[key] = value.split(',') 194 195 # Let every filter spec modify the qs and params to its liking 196 for filter_spec in self.filter_specs: 197 new_qs = filter_spec.get_query_set(self, qs) 198 if new_qs: 199 qs = new_qs 200 # Only consume params if we got a new queryset 201 for param in filter_spec.consumed_params(): 202 try: 203 del lookup_params[param] 204 except KeyError: 205 pass 186 206 187 207 # Apply lookup parameters from the query string. 188 208 try: