Loading django/contrib/admin/filters.py +21 −3 Original line number Diff line number Diff line Loading @@ -269,25 +269,43 @@ FieldListFilter.register( class ChoicesFieldListFilter(FieldListFilter): def __init__(self, field, request, params, model, model_admin, 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_isnull = request.GET.get(self.lookup_kwarg_isnull) super(ChoicesFieldListFilter, self).__init__( field, request, params, model, model_admin, field_path) def expected_parameters(self): return [self.lookup_kwarg] return [self.lookup_kwarg, self.lookup_kwarg_isnull] def choices(self, changelist): yield { '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') } none_title = '' for lookup, title in self.field.flatchoices: if lookup is None: none_title = title continue yield { '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, } 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) Loading tests/admin_filters/models.py +7 −0 Original line number Diff line number Diff line Loading @@ -75,5 +75,12 @@ class Bookmark(models.Model): url = models.URLField() 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): return self.url tests/admin_filters/tests.py +16 −0 Original line number Diff line number Diff line Loading @@ -302,6 +302,22 @@ class ListFiltersTests(TestCase): 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): modeladmin = BookAdmin(Book, site) Loading Loading
django/contrib/admin/filters.py +21 −3 Original line number Diff line number Diff line Loading @@ -269,25 +269,43 @@ FieldListFilter.register( class ChoicesFieldListFilter(FieldListFilter): def __init__(self, field, request, params, model, model_admin, 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_isnull = request.GET.get(self.lookup_kwarg_isnull) super(ChoicesFieldListFilter, self).__init__( field, request, params, model, model_admin, field_path) def expected_parameters(self): return [self.lookup_kwarg] return [self.lookup_kwarg, self.lookup_kwarg_isnull] def choices(self, changelist): yield { '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') } none_title = '' for lookup, title in self.field.flatchoices: if lookup is None: none_title = title continue yield { '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, } 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) Loading
tests/admin_filters/models.py +7 −0 Original line number Diff line number Diff line Loading @@ -75,5 +75,12 @@ class Bookmark(models.Model): url = models.URLField() 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): return self.url
tests/admin_filters/tests.py +16 −0 Original line number Diff line number Diff line Loading @@ -302,6 +302,22 @@ class ListFiltersTests(TestCase): 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): modeladmin = BookAdmin(Book, site) Loading