Ticket #3400: 3400-against-10680-with-tests-docs.patch
File 3400-against-10680-with-tests-docs.patch, 14.0 KB (added by , 16 years ago) |
---|
-
django/contrib/admin/filterspecs.py
diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py index 6f643ee..7f473a2 100644
a b import datetime 15 15 16 16 class FilterSpec(object): 17 17 filter_specs = [] 18 def __init__(self, f, request, params, model, model_admin ):18 def __init__(self, f, request, params, model, model_admin, field_path=None): 19 19 self.field = f 20 20 self.params = params 21 self.field_path = field_path or f.name 21 22 22 23 def register(cls, test, factory): 23 24 cls.filter_specs.append((test, factory)) 24 25 register = classmethod(register) 25 26 26 def create(cls, f, request, params, model, model_admin ):27 def create(cls, f, request, params, model, model_admin, field_path=None): 27 28 for test, factory in cls.filter_specs: 28 29 if test(f): 29 return factory(f, request, params, model, model_admin )30 return factory(f, request, params, model, model_admin, field_path=field_path) 30 31 create = classmethod(create) 31 32 32 33 def has_output(self): … … class FilterSpec(object): 52 53 return mark_safe("".join(t)) 53 54 54 55 class RelatedFilterSpec(FilterSpec): 55 def __init__(self, f, request, params, model, model_admin ):56 super(RelatedFilterSpec, self).__init__(f, request, params, model, model_admin )56 def __init__(self, f, request, params, model, model_admin, field_path=None): 57 super(RelatedFilterSpec, self).__init__(f, request, params, model, model_admin, field_path=field_path) 57 58 if isinstance(f, models.ManyToManyField): 58 59 self.lookup_title = f.rel.to._meta.verbose_name 59 60 else: 60 61 self.lookup_title = f.verbose_name 61 rel_name = f.rel. get_related_field().name62 self.lookup_kwarg = '%s__%s__exact' % ( f.name, rel_name)62 rel_name = f.rel.to._meta.pk.name 63 self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name) 63 64 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 64 65 self.lookup_choices = f.get_choices(include_blank=False) 65 66 … … class RelatedFilterSpec(FilterSpec): 81 82 FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec) 82 83 83 84 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.name85 def __init__(self, f, request, params, model, model_admin, field_path=None): 86 super(ChoicesFilterSpec, self).__init__(f, request, params, model, model_admin, field_path=field_path) 87 self.lookup_kwarg = '%s__exact' % self.field_path 87 88 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 88 89 89 90 def choices(self, cl): … … class ChoicesFilterSpec(FilterSpec): 98 99 FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec) 99 100 100 101 class DateFieldFilterSpec(FilterSpec): 101 def __init__(self, f, request, params, model, model_admin ):102 super(DateFieldFilterSpec, self).__init__(f, request, params, model, model_admin )102 def __init__(self, f, request, params, model, model_admin, field_path=None): 103 super(DateFieldFilterSpec, self).__init__(f, request, params, model, model_admin, field_path=field_path) 103 104 104 self.field_generic = '%s__' % self.field .name105 self.field_generic = '%s__' % self.field_path 105 106 106 107 self.date_params = dict([(k, v) for k, v in params.items() if k.startswith(self.field_generic)]) 107 108 … … class DateFieldFilterSpec(FilterSpec): 111 112 112 113 self.links = ( 113 114 (_('Any date'), {}), 114 (_('Today'), {'%s__year' % self.field .name: str(today.year),115 '%s__month' % self.field .name: str(today.month),116 '%s__day' % self.field .name: str(today.day)}),117 (_('Past 7 days'), {'%s__gte' % self.field .name: one_week_ago.strftime('%Y-%m-%d'),118 '%s__lte' % f.name: today_str}),119 (_('This month'), {'%s__year' % self.field .name: str(today.year),120 '%s__month' % f.name: str(today.month)}),121 (_('This year'), {'%s__year' % self.field .name: str(today.year)})115 (_('Today'), {'%s__year' % self.field_path: str(today.year), 116 '%s__month' % self.field_path: str(today.month), 117 '%s__day' % self.field_path: str(today.day)}), 118 (_('Past 7 days'), {'%s__gte' % self.field_path: one_week_ago.strftime('%Y-%m-%d'), 119 '%s__lte' % self.field_path: today_str}), 120 (_('This month'), {'%s__year' % self.field_path: str(today.year), 121 '%s__month' % self.field_path: str(today.month)}), 122 (_('This year'), {'%s__year' % self.field_path: str(today.year)}) 122 123 ) 123 124 124 125 def title(self): … … class DateFieldFilterSpec(FilterSpec): 133 134 FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec) 134 135 135 136 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.name139 self.lookup_kwarg2 = '%s__isnull' % f.name137 def __init__(self, f, request, params, model, model_admin, field_path=None): 138 super(BooleanFieldFilterSpec, self).__init__(f, request, params, model, model_admin, field_path=field_path) 139 self.lookup_kwarg = '%s__exact' % self.field_path 140 self.lookup_kwarg2 = '%s__isnull' % self.field_path 140 141 self.lookup_val = request.GET.get(self.lookup_kwarg, None) 141 142 self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None) 142 143 … … FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f 159 160 # if a field is eligible to use the BooleanFieldFilterSpec, that'd be much 160 161 # more appropriate, and the AllValuesFilterSpec won't get used for it. 161 162 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) 163 def __init__(self, f, request, params, model, model_admin, field_path=None): 164 super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin, field_path=field_path) 165 self.lookup_val = request.GET.get(self.field_path, None) 166 #self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name) 167 self.lookup_choices = model._default_manager.all().distinct().order_by(f.name).values(f.name) 166 168 167 169 def title(self): 168 170 return self.field.verbose_name 169 171 170 172 def choices(self, cl): 171 173 yield {'selected': self.lookup_val is None, 172 'query_string': cl.get_query_string({}, [self.field .name]),174 'query_string': cl.get_query_string({}, [self.field_path]), 173 175 'display': _('All')} 174 176 for val in self.lookup_choices: 175 177 val = smart_unicode(val[self.field.name]) 176 178 yield {'selected': self.lookup_val == val, 177 'query_string': cl.get_query_string({self.field .name: val}),179 'query_string': cl.get_query_string({self.field_path: val}), 178 180 'display': val} 179 181 FilterSpec.register(lambda f: True, AllValuesFilterSpec) -
django/contrib/admin/validation.py
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 4bef007..70d2dfc 100644
a b def check_isdict(cls, label, obj): 279 279 280 280 def get_field(cls, model, opts, label, field): 281 281 try: 282 return opts.get_field(field) 282 if '__' in field: 283 f = None 284 m = model 285 path = field.split('__') 286 for field_name in path[:-1]: 287 f = model._meta.get_field(field_name) 288 model = f.rel.to 289 return opts.get_field(path[0]) 290 else: 291 return opts.get_field(field) 283 292 except models.FieldDoesNotExist: 284 293 raise ImproperlyConfigured("'%s.%s' refers to field '%s' that is missing from model '%s'." 285 294 % (cls.__name__, label, field, model.__name__)) -
django/contrib/admin/views/main.py
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 95f4ca7..2342b66 100644
a b class ChangeList(object): 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 lookup_opts = self.lookup_opts 78 for filter_name in self.list_filter: 79 if '__' in filter_name: 80 f = None 81 model = self.model 82 path = filter_name.split('__') 83 for field_name in path[:-1]: 84 f = model._meta.get_field(field_name) 85 model = f.rel.to 86 f = model._meta.get_field(path[-1]) 87 spec = FilterSpec.create(f, request, self.params, model, self.model_admin, field_path=filter_name) 88 else: 89 f = lookup_opts.get_field(filter_name) 90 spec = FilterSpec.create(f, request, self.params, self.model, self.model_admin) 80 91 if spec and spec.has_output(): 81 92 filter_specs.append(spec) 82 93 return filter_specs, bool(filter_specs) -
docs/ref/contrib/admin/index.txt
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 700303f..263f4c2 100644
a b how both ``list_display`` and ``list_filter`` work:: 446 446 list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') 447 447 list_filter = ('is_staff', 'is_superuser') 448 448 449 In ``list_filter`` can be defined lookup separator as well:: 450 451 class UserAdminWithLookup(UserAdmin): 452 list_filter = ('groups__name') 453 449 454 The above code results in an admin change list page that looks like this: 450 455 451 456 .. image:: _images/users_changelist.png -
new file tests/regressiontests/admin_filters/fixtures/admin-filter-data.json
diff --git a/tests/regressiontests/admin_filters/__init__.py b/tests/regressiontests/admin_filters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regressiontests/admin_filters/fixtures/admin-filter-data.json b/tests/regressiontests/admin_filters/fixtures/admin-filter-data.json new file mode 100644 index 0000000..93aa48c
- + 1 [ 2 { 3 "pk": 1, 4 "model": "admin_filters.filterable", 5 "fields": { 6 "sites": [1] 7 } 8 }, 9 { 10 "pk": 2, 11 "model": "admin_filters.filterable", 12 "fields": { 13 "sites": [1] 14 } 15 } 16 ] -
new file tests/regressiontests/admin_filters/fixtures/admin-filter-user.json
diff --git a/tests/regressiontests/admin_filters/fixtures/admin-filter-user.json b/tests/regressiontests/admin_filters/fixtures/admin-filter-user.json new file mode 100644 index 0000000..33ae10e
- + 1 [ 2 { 3 "pk": 1, 4 "model": "auth.user", 5 "fields": { 6 "username": "admin", 7 "first_name": "", 8 "last_name": "", 9 "is_active": true, 10 "is_superuser": true, 11 "is_staff": true, 12 "last_login": "2009-03-30 22:05:28", 13 "groups": [], 14 "user_permissions": [], 15 "password": "sha1$6d71f$d2b636e70cbd76dd4138766efffc46f30bcc5895", 16 "email": "a@a.cz", 17 "date_joined": "2009-03-30 22:05:28" 18 } 19 } 20 ] -
new file tests/regressiontests/admin_filters/models.py
diff --git a/tests/regressiontests/admin_filters/models.py b/tests/regressiontests/admin_filters/models.py new file mode 100644 index 0000000..6c28ae2
- + 1 from django.db import models 2 from django.contrib.sites.models import Site 3 4 class Filterable(models.Model): 5 sites = models.ManyToManyField(Site, blank=True) 6 7 8 from django.contrib import admin 9 10 class FilterableAdmin(admin.ModelAdmin): 11 list_filter = ('sites__domain',) 12 13 admin.site.register(Filterable, FilterableAdmin) 14 -
new file tests/regressiontests/admin_filters/tests.py
diff --git a/tests/regressiontests/admin_filters/tests.py b/tests/regressiontests/admin_filters/tests.py new file mode 100644 index 0000000..4b71c1a
- + 1 from django.test import TestCase 2 3 4 class AdminFilters(TestCase): 5 fixtures = ['admin-filter-user.json', 'admin-filter-data.json'] 6 admin_url = '/test_admin/admin' 7 8 def setUp(self): 9 self.client.login(username='admin', password='admin') 10 11 def tearDown(self): 12 self.client.logout() 13 14 def test_filters_are_enabled(self): 15 """ 16 log superuser in and go to filtered page 17 """ 18 response = self.client.get('%s/admin_filters/filterable/' % self.admin_url, {'sites__domain': 'example.com'}) 19 20 self.failUnlessEqual(response.status_code, 200) 21 self.failUnlessEqual('2 filterables' in response.content, True) 22 -
new file tests/regressiontests/admin_filters/urls.py
diff --git a/tests/regressiontests/admin_filters/urls.py b/tests/regressiontests/admin_filters/urls.py new file mode 100644 index 0000000..4fdfeb4
- + 1 from django.conf.urls.defaults import * 2 from django.contrib import admin 3 4 urlpatterns = patterns('', 5 (r'^admin/doc/', include('django.contrib.admindocs.urls')), 6 (r'^admin/', include(admin.site.urls)), 7 )