diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
index b4f2b9d..1deef1d 100644
a
|
b
|
def validate(cls, model):
|
73 | 73 | " associated with a field name." |
74 | 74 | % (cls.__name__, idx, item.__name__)) |
75 | 75 | else: |
76 | | try: |
77 | | # Check for option #2 (tuple) |
78 | | field, list_filter_class = item |
79 | | except (TypeError, ValueError): |
80 | | # item is option #1 |
81 | | field = item |
82 | | else: |
| 76 | if type(item) == tuple and len(item) == 2: |
83 | 77 | # item is option #2 |
| 78 | field, list_filter_class = item |
84 | 79 | if not issubclass(list_filter_class, FieldListFilter): |
85 | 80 | raise ImproperlyConfigured("'%s.list_filter[%d][1]'" |
86 | 81 | " is '%s' which is not of type FieldListFilter." |
87 | 82 | % (cls.__name__, idx, list_filter_class.__name__)) |
| 83 | else: |
| 84 | # item is option #1 |
| 85 | field = item |
88 | 86 | # Validate the field string |
89 | 87 | try: |
90 | 88 | get_fields_from_path(model, field) |
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index d5f401c..cfe919f 100644
a
|
b
|
class ChangeList(object):
|
97 | 97 | self.model, self.model_admin) |
98 | 98 | else: |
99 | 99 | field_path = None |
100 | | try: |
101 | | # This is custom FieldListFilter class for a given field. |
| 100 | if type(list_filer) == tuple: |
| 101 | # This is a custom FieldListFilter class for a given field. |
102 | 102 | field, field_list_filter_class = list_filer |
103 | | except (TypeError, ValueError): |
| 103 | else: |
104 | 104 | # This is simply a field name, so use the default |
105 | 105 | # FieldListFilter class that has been registered for |
106 | 106 | # the type of the given field. |
diff --git a/tests/regressiontests/admin_filters/models.py b/tests/regressiontests/admin_filters/models.py
index 80d54c7..fbf14e8 100644
a
|
b
|
class Book(models.Model):
|
8 | 8 | contributors = models.ManyToManyField(User, related_name='books_contributed', blank=True, null=True) |
9 | 9 | is_best_seller = models.NullBooleanField(default=0) |
10 | 10 | date_registered = models.DateField(null=True) |
| 11 | no = models.IntegerField(verbose_name=u'number', blank=True, null=True) # This field is intentionally 2 characters long. See #16080. |
11 | 12 | |
12 | 13 | def __unicode__(self): |
13 | 14 | return self.title |
diff --git a/tests/regressiontests/admin_filters/tests.py b/tests/regressiontests/admin_filters/tests.py
index f5542dd..b208b2a 100644
a
|
b
|
class CustomUserAdmin(UserAdmin):
|
66 | 66 | list_filter = ('books_authored', 'books_contributed') |
67 | 67 | |
68 | 68 | class BookAdmin(ModelAdmin): |
69 | | list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered') |
| 69 | list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered', 'no') |
70 | 70 | order_by = '-id' |
71 | 71 | |
72 | 72 | class DecadeFilterBookAdmin(ModelAdmin): |
… |
… |
class ListFiltersTests(TestCase):
|
100 | 100 | |
101 | 101 | # Books |
102 | 102 | self.djangonaut_book = Book.objects.create(title='Djangonaut: an art of living', year=2009, author=self.alfred, is_best_seller=True, date_registered=self.today) |
103 | | self.bio_book = Book.objects.create(title='Django: a biography', year=1999, author=self.alfred, is_best_seller=False) |
104 | | self.django_book = Book.objects.create(title='The Django Book', year=None, author=self.bob, is_best_seller=None, date_registered=self.today) |
| 103 | self.bio_book = Book.objects.create(title='Django: a biography', year=1999, author=self.alfred, is_best_seller=False, no=207) |
| 104 | self.django_book = Book.objects.create(title='The Django Book', year=None, author=self.bob, is_best_seller=None, date_registered=self.today, no=103) |
105 | 105 | self.gipsy_book = Book.objects.create(title='Gipsy guitar for dummies', year=2002, is_best_seller=True, date_registered=self.one_week_ago) |
106 | 106 | self.gipsy_book.contributors = [self.bob, self.lisa] |
107 | 107 | self.gipsy_book.save() |
… |
… |
class ListFiltersTests(TestCase):
|
528 | 528 | self.assertEqual(choices[2]['display'], u'the 2000\'s') |
529 | 529 | self.assertEqual(choices[2]['selected'], False) |
530 | 530 | self.assertEqual(choices[2]['query_string'], '?publication-decade=the+00s') |
| 531 | |
| 532 | def test_two_characters_long_field(self): |
| 533 | """ |
| 534 | Ensure that list_filter works with two-characters long field names. |
| 535 | Refs #16080. |
| 536 | """ |
| 537 | modeladmin = BookAdmin(Book, site) |
| 538 | |
| 539 | request = self.request_factory.get('/', {'no': '207'}) |
| 540 | changelist = self.get_changelist(request, Book, modeladmin) |
| 541 | |
| 542 | # Make sure the correct queryset is returned |
| 543 | queryset = changelist.get_query_set(request) |
| 544 | self.assertEqual(list(queryset), [self.bio_book]) |
| 545 | |
| 546 | |
| 547 | filterspec = changelist.get_filters(request)[0][-1] |
| 548 | self.assertEqual(force_unicode(filterspec.title), u'number') |
| 549 | choices = list(filterspec.choices(changelist)) |
| 550 | self.assertEqual(choices[2]['selected'], True) |
| 551 | self.assertEqual(choices[2]['query_string'], '?no=207') |
diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py
index 2eda54e..26eaaae 100644
a
|
b
|
class ValidationTestModel(models.Model):
|
34 | 34 | is_active = models.BooleanField() |
35 | 35 | pub_date = models.DateTimeField() |
36 | 36 | band = models.ForeignKey(Band) |
| 37 | no = models.IntegerField(verbose_name="Number", blank=True, null=True) # This field is intentionally 2 characters long. See #16080. |
37 | 38 | |
38 | 39 | def decade_published_in(self): |
39 | 40 | return self.pub_date.strftime('%Y')[:3] + "0's" |
diff --git a/tests/regressiontests/modeladmin/tests.py b/tests/regressiontests/modeladmin/tests.py
index 530b476..7387a95 100644
a
|
b
|
class ValidationTests(unittest.TestCase):
|
911 | 911 | # Valid declarations below ----------- |
912 | 912 | |
913 | 913 | class ValidationTestModelAdmin(ModelAdmin): |
914 | | list_filter = ('is_active', AwesomeFilter, ('is_active', BooleanFieldListFilter)) |
| 914 | list_filter = ('is_active', AwesomeFilter, ('is_active', BooleanFieldListFilter), 'no') |
915 | 915 | |
916 | 916 | validate(ValidationTestModelAdmin, ValidationTestModel) |
917 | 917 | |