Fixed #26277 -- Added support for null values in ChoicesFieldListFilter.

This commit is contained in:
Vincenzo Pandolfo 2016-03-30 16:05:31 +01:00 committed by Tim Graham
parent 929684d6ee
commit 069319396f
3 changed files with 44 additions and 3 deletions

View File

@ -269,25 +269,43 @@ FieldListFilter.register(
class ChoicesFieldListFilter(FieldListFilter): class ChoicesFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path): def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = '%s__exact' % field_path self.lookup_kwarg = '%s__exact' % field_path
self.lookup_kwarg_isnull = '%s__isnull' % field_path
self.lookup_val = request.GET.get(self.lookup_kwarg) self.lookup_val = request.GET.get(self.lookup_kwarg)
self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull)
super(ChoicesFieldListFilter, self).__init__( super(ChoicesFieldListFilter, self).__init__(
field, request, params, model, model_admin, field_path) field, request, params, model, model_admin, field_path)
def expected_parameters(self): def expected_parameters(self):
return [self.lookup_kwarg] return [self.lookup_kwarg, self.lookup_kwarg_isnull]
def choices(self, changelist): def choices(self, changelist):
yield { yield {
'selected': self.lookup_val is None, 'selected': self.lookup_val is None,
'query_string': changelist.get_query_string({}, [self.lookup_kwarg]), 'query_string': changelist.get_query_string(
{}, [self.lookup_kwarg, self.lookup_kwarg_isnull]
),
'display': _('All') 'display': _('All')
} }
none_title = ''
for lookup, title in self.field.flatchoices: for lookup, title in self.field.flatchoices:
if lookup is None:
none_title = title
continue
yield { yield {
'selected': smart_text(lookup) == self.lookup_val, 'selected': smart_text(lookup) == self.lookup_val,
'query_string': changelist.get_query_string({self.lookup_kwarg: lookup}), 'query_string': changelist.get_query_string(
{self.lookup_kwarg: lookup}, [self.lookup_kwarg_isnull]
),
'display': title, 'display': title,
} }
if none_title:
yield {
'selected': bool(self.lookup_val_isnull),
'query_string': changelist.get_query_string({
self.lookup_kwarg_isnull: 'True',
}, [self.lookup_kwarg]),
'display': none_title,
}
FieldListFilter.register(lambda f: bool(f.choices), ChoicesFieldListFilter) FieldListFilter.register(lambda f: bool(f.choices), ChoicesFieldListFilter)

View File

@ -75,5 +75,12 @@ class Bookmark(models.Model):
url = models.URLField() url = models.URLField()
tags = GenericRelation(TaggedItem) tags = GenericRelation(TaggedItem)
CHOICES = [
('a', 'A'),
(None, 'None'),
('', '-'),
]
none_or_null = models.CharField(max_length=20, choices=CHOICES, blank=True, null=True)
def __str__(self): def __str__(self):
return self.url return self.url

View File

@ -302,6 +302,22 @@ class ListFiltersTests(TestCase):
modeladmin.list_max_show_all, modeladmin.list_editable, modeladmin, modeladmin.list_max_show_all, modeladmin.list_editable, modeladmin,
) )
def test_choicesfieldlistfilter_has_none_choice(self):
"""
The last choice is for the None value.
"""
class BookmarkChoicesAdmin(ModelAdmin):
list_display = ['none_or_null']
list_filter = ['none_or_null']
modeladmin = BookmarkChoicesAdmin(Bookmark, site)
request = self.request_factory.get('/', {})
changelist = self.get_changelist(request, Bookmark, modeladmin)
filterspec = changelist.get_filters(request)[0][0]
choices = list(filterspec.choices(changelist))
self.assertEqual(choices[-1]['display'], 'None')
self.assertEqual(choices[-1]['query_string'], '?none_or_null__isnull=True')
def test_datefieldlistfilter(self): def test_datefieldlistfilter(self):
modeladmin = BookAdmin(Book, site) modeladmin = BookAdmin(Book, site)