Ticket #5833: 5833.patch
File 5833.patch, 14.6 KB (added by , 15 years ago) |
---|
-
django/contrib/admin/__init__.py
diff --git a/django/contrib/admin/__init__.py b/django/contrib/admin/__init__.py index 8105976..a80444e 100644
a b from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME 2 2 from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL 3 3 from django.contrib.admin.options import StackedInline, TabularInline 4 4 from django.contrib.admin.sites import AdminSite, site 5 from django.contrib.admin.filterspecs import FilterSpec, FieldFilterSpec 5 6 from django.utils.importlib import import_module 6 7 7 8 # A flag to tell us if autodiscover is running. autodiscover will set this to -
django/contrib/admin/filterspecs.py
diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py index 6f643ee..10cef73 100644
a b from django.utils.safestring import mark_safe 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 = [] … … class FilterSpec(object): 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: … … class RelatedFilterSpec(FilterSpec): 78 104 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}), 79 105 'display': val} 80 106 81 Fi lterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)107 FieldFilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec, False) 82 108 83 class ChoicesFilterSpec(Fi lterSpec):84 def __init__(self, f, request, params, model, model_admin):85 super(ChoicesFilterSpec, self).__init__( f, request, params, model, model_admin)109 class ChoicesFilterSpec(FieldFilterSpec): 110 def __init__(self, request, params, model, model_admin, f): 111 super(ChoicesFilterSpec, self).__init__(request, params, model, model_admin, f) 86 112 self.lookup_kwarg = '%s__exact' % f.name 87 113 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 88 114 … … class ChoicesFilterSpec(FilterSpec): 95 121 'query_string': cl.get_query_string({self.lookup_kwarg: k}), 96 122 'display': v} 97 123 98 Fi lterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)124 FieldFilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec, False) 99 125 100 class DateFieldFilterSpec(Fi lterSpec):101 def __init__(self, f, request, params, model, model_admin):102 super(DateFieldFilterSpec, self).__init__( f, request, params, model, model_admin)126 class DateFieldFilterSpec(FieldFilterSpec): 127 def __init__(self, request, params, model, model_admin, f): 128 super(DateFieldFilterSpec, self).__init__(request, params, model, model_admin, f) 103 129 104 130 self.field_generic = '%s__' % self.field.name 105 131 … … class DateFieldFilterSpec(FilterSpec): 121 147 (_('This year'), {'%s__year' % self.field.name: str(today.year)}) 122 148 ) 123 149 124 def title(self):125 return self.field.verbose_name126 127 150 def choices(self, cl): 128 151 for title, param_dict in self.links: 129 152 yield {'selected': self.date_params == param_dict, 130 153 'query_string': cl.get_query_string(param_dict, [self.field_generic]), 131 154 'display': title} 132 155 133 Fi lterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)156 FieldFilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec, False) 134 157 135 class BooleanFieldFilterSpec(Fi lterSpec):136 def __init__(self, f, request, params, model, model_admin):137 super(BooleanFieldFilterSpec, self).__init__( f, request, params, model, model_admin)158 class BooleanFieldFilterSpec(FieldFilterSpec): 159 def __init__(self, request, params, model, model_admin, f): 160 super(BooleanFieldFilterSpec, self).__init__(request, params, model, model_admin, f) 138 161 self.lookup_kwarg = '%s__exact' % f.name 139 162 self.lookup_kwarg2 = '%s__isnull' % f.name 140 163 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 141 164 self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None) 142 165 143 def title(self):144 return self.field.verbose_name145 146 166 def choices(self, cl): 147 167 for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')): 148 168 yield {'selected': self.lookup_val == v and not self.lookup_val2, … … class BooleanFieldFilterSpec(FilterSpec): 153 173 'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]), 154 174 'display': _('Unknown')} 155 175 156 Fi lterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)176 FieldFilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec, False) 157 177 158 178 # This should be registered last, because it's a last resort. For example, 159 179 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much 160 180 # more appropriate, and the AllValuesFilterSpec won't get used for it. 161 class AllValuesFilterSpec(Fi lterSpec):162 def __init__(self, f, request, params, model, model_admin):163 super(AllValuesFilterSpec, self).__init__( f, request, params, model, model_admin)181 class AllValuesFilterSpec(FieldFilterSpec): 182 def __init__(self, request, params, model, model_admin, f): 183 super(AllValuesFilterSpec, self).__init__(request, params, model, model_admin, f) 164 184 self.lookup_val = request.GET.get(f.name, None) 165 185 self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name) 166 186 167 def title(self):168 return self.field.verbose_name169 170 187 def choices(self, cl): 171 188 yield {'selected': self.lookup_val is None, 172 189 'query_string': cl.get_query_string({}, [self.field.name]), … … class AllValuesFilterSpec(FilterSpec): 176 193 yield {'selected': self.lookup_val == val, 177 194 'query_string': cl.get_query_string({self.field.name: val}), 178 195 'display': val} 179 Fi lterSpec.register(lambda f: True, AllValuesFilterSpec)196 FieldFilterSpec.register(lambda f: True, AllValuesFilterSpec, False) -
django/contrib/admin/validation.py
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 50e4143..c72515e 100644
a b from django.db import models 8 8 from django.forms.models import BaseModelForm, BaseModelFormSet, fields_for_model, _get_foreign_key 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 … … def validate(cls, model): 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) and not isinstance(item, models.Field): 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, factory = item 71 except (TypeError, ValueError): 72 field = 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 if not isinstance(field, models.Field): 80 get_field(cls, model, opts, 'list_filter[%d]' % idx, field) 81 elif not isinstance(item, models.Field): 82 get_field(cls, model, opts, 'list_filter[%d]' % idx, item) 61 83 62 84 # list_per_page = 100 63 85 if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int): -
django/contrib/admin/views/main.py
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index df0fd9f..da01a82 100644
a b 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 … … class ChangeList(object): 63 63 if ERROR_FLAG in self.params: 64 64 del self.params[ERROR_FLAG] 65 65 66 self.filter_specs, self.has_filters = self.get_filters(request) 66 67 self.order_field, self.order_type = self.get_ordering() 67 68 self.query = request.GET.get(SEARCH_VAR, '') 68 69 self.query_set = self.get_query_set() 69 70 self.get_results(request) 70 71 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)) 71 self.filter_specs, self.has_filters = self.get_filters(request)72 72 self.pk_attname = self.lookup_opts.pk.attname 73 73 74 74 def get_filters(self, request): 75 75 filter_specs = [] 76 76 if self.list_filter: 77 filter_fields = [self.lookup_opts.get_field(field_name) for field_name in self.list_filter] 78 for f in filter_fields: 79 spec = FilterSpec.create(f, request, self.params, self.model, self.model_admin) 77 for item in self.list_filter: 78 if callable(item): 79 spec = item(request, self.params, self.model, self.model_admin) 80 else: 81 try: 82 field, factory = item 83 except (TypeError, ValueError): 84 field, factory = item, FieldFilterSpec.create 85 if not isinstance(field, models.Field): 86 field = self.lookup_opts.get_field(field) 87 spec = factory(request, self.params, self.model, 88 self.model_admin, field) 80 89 if spec and spec.has_output(): 81 90 filter_specs.append(spec) 82 91 return filter_specs, bool(filter_specs) … … class ChangeList(object): 184 193 # if key ends with __in, split parameter into separate values 185 194 if key.endswith('__in'): 186 195 lookup_params[key] = value.split(',') 196 197 # Let every filter spec modify the qs and params to its liking 198 for filter_spec in self.filter_specs: 199 new_qs = filter_spec.get_query_set(self, qs) 200 if new_qs: 201 qs = new_qs 202 # Only consume params if we got a new queryset 203 for param in filter_spec.consumed_params(): 204 try: 205 del lookup_params[param] 206 except KeyError: 207 pass 187 208 188 209 # Apply lookup parameters from the query string. 189 210 try: