Commit 06931939 authored by Vincenzo Pandolfo's avatar Vincenzo Pandolfo Committed by Tim Graham
Browse files

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

parent 929684d6
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -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)

+7 −0
Original line number Diff line number Diff line
@@ -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
+16 −0
Original line number Diff line number Diff line
@@ -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)