diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index 3e02cd89d7..7f4690806b 100644 --- a/django/contrib/admin/filters.py +++ b/django/contrib/admin/filters.py @@ -244,10 +244,12 @@ class BooleanFieldListFilter(FieldListFilter): return [self.lookup_kwarg, self.lookup_kwarg2] def choices(self, changelist): + field_choices = dict(self.field.flatchoices) for lookup, title in ( - (None, _('All')), - ('1', _('Yes')), - ('0', _('No'))): + (None, _('All')), + ('1', field_choices.get(True, _('Yes'))), + ('0', field_choices.get(False, _('No'))), + ): yield { 'selected': self.lookup_val == lookup and not self.lookup_val2, 'query_string': changelist.get_query_string({self.lookup_kwarg: lookup}, [self.lookup_kwarg2]), @@ -257,7 +259,7 @@ class BooleanFieldListFilter(FieldListFilter): yield { 'selected': self.lookup_val2 == 'True', 'query_string': changelist.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]), - 'display': _('Unknown'), + 'display': field_choices.get(None, _('Unknown')), } diff --git a/tests/admin_filters/models.py b/tests/admin_filters/models.py index cee3af5b90..f286e641de 100644 --- a/tests/admin_filters/models.py +++ b/tests/admin_filters/models.py @@ -31,6 +31,11 @@ class Book(models.Model): is_best_seller = models.BooleanField(default=0, null=True) is_best_seller2 = models.NullBooleanField(default=0) date_registered = models.DateField(null=True) + availability = models.BooleanField(choices=( + (False, 'Paid'), + (True, 'Free'), + (None, 'Obscure'), + ), null=True) # This field name is intentionally 2 characters long (#16080). no = models.IntegerField(verbose_name='number', blank=True, null=True) diff --git a/tests/admin_filters/tests.py b/tests/admin_filters/tests.py index 16a7ce495c..6986afb64a 100644 --- a/tests/admin_filters/tests.py +++ b/tests/admin_filters/tests.py @@ -140,7 +140,7 @@ class CustomUserAdmin(UserAdmin): class BookAdmin(ModelAdmin): - list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered', 'no') + list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered', 'no', 'availability') ordering = ('-id',) @@ -156,6 +156,7 @@ class BookAdminWithTupleBooleanFilter(BookAdmin): ('is_best_seller', BooleanFieldListFilter), 'date_registered', 'no', + ('availability', BooleanFieldListFilter), ) @@ -288,22 +289,22 @@ class ListFiltersTests(TestCase): cls.djangonaut_book = Book.objects.create( title='Djangonaut: an art of living', year=2009, author=cls.alfred, is_best_seller=True, date_registered=cls.today, - is_best_seller2=True, + is_best_seller2=True, availability=True, ) cls.bio_book = Book.objects.create( title='Django: a biography', year=1999, author=cls.alfred, is_best_seller=False, no=207, - is_best_seller2=False, + is_best_seller2=False, availability=False, ) cls.django_book = Book.objects.create( title='The Django Book', year=None, author=cls.bob, is_best_seller=None, date_registered=cls.today, no=103, - is_best_seller2=None, + is_best_seller2=None, availability=True, ) cls.guitar_book = Book.objects.create( title='Guitar for dummies', year=2002, is_best_seller=True, date_registered=cls.one_week_ago, - is_best_seller2=True, + is_best_seller2=True, availability=None, ) cls.guitar_book.contributors.set([cls.bob, cls.lisa]) @@ -956,6 +957,63 @@ class ListFiltersTests(TestCase): self.assertIs(choice['selected'], True) self.assertEqual(choice['query_string'], '?is_best_seller__isnull=True') + def test_booleanfieldlistfilter_choices(self): + modeladmin = BookAdmin(Book, site) + self.verify_booleanfieldlistfilter_choices(modeladmin) + + def test_booleanfieldlistfilter_tuple_choices(self): + modeladmin = BookAdminWithTupleBooleanFilter(Book, site) + self.verify_booleanfieldlistfilter_choices(modeladmin) + + def verify_booleanfieldlistfilter_choices(self, modeladmin): + # False. + request = self.request_factory.get('/', {'availability__exact': 0}) + request.user = self.alfred + changelist = modeladmin.get_changelist_instance(request) + queryset = changelist.get_queryset(request) + self.assertEqual(list(queryset), [self.bio_book]) + filterspec = changelist.get_filters(request)[0][6] + self.assertEqual(filterspec.title, 'availability') + choice = select_by(filterspec.choices(changelist), 'display', 'Paid') + self.assertIs(choice['selected'], True) + self.assertEqual(choice['query_string'], '?availability__exact=0') + # True. + request = self.request_factory.get('/', {'availability__exact': 1}) + request.user = self.alfred + changelist = modeladmin.get_changelist_instance(request) + queryset = changelist.get_queryset(request) + self.assertEqual(list(queryset), [self.django_book, self.djangonaut_book]) + filterspec = changelist.get_filters(request)[0][6] + self.assertEqual(filterspec.title, 'availability') + choice = select_by(filterspec.choices(changelist), 'display', 'Free') + self.assertIs(choice['selected'], True) + self.assertEqual(choice['query_string'], '?availability__exact=1') + # None. + request = self.request_factory.get('/', {'availability__isnull': 'True'}) + request.user = self.alfred + changelist = modeladmin.get_changelist_instance(request) + queryset = changelist.get_queryset(request) + self.assertEqual(list(queryset), [self.guitar_book]) + filterspec = changelist.get_filters(request)[0][6] + self.assertEqual(filterspec.title, 'availability') + choice = select_by(filterspec.choices(changelist), 'display', 'Obscure') + self.assertIs(choice['selected'], True) + self.assertEqual(choice['query_string'], '?availability__isnull=True') + # All. + request = self.request_factory.get('/') + request.user = self.alfred + changelist = modeladmin.get_changelist_instance(request) + queryset = changelist.get_queryset(request) + self.assertEqual( + list(queryset), + [self.guitar_book, self.django_book, self.bio_book, self.djangonaut_book], + ) + filterspec = changelist.get_filters(request)[0][6] + self.assertEqual(filterspec.title, 'availability') + choice = select_by(filterspec.choices(changelist), 'display', 'All') + self.assertIs(choice['selected'], True) + self.assertEqual(choice['query_string'], '?') + def test_booleanfieldlistfilter_nullbooleanfield(self): modeladmin = BookAdmin2(Book, site) @@ -1212,7 +1270,7 @@ class ListFiltersTests(TestCase): queryset = changelist.get_queryset(request) self.assertEqual(list(queryset), [self.bio_book]) - filterspec = changelist.get_filters(request)[0][-1] + filterspec = changelist.get_filters(request)[0][5] self.assertEqual(filterspec.title, 'number') choices = list(filterspec.choices(changelist)) self.assertIs(choices[2]['selected'], True)