rocktheparty
rocktheparty

Reputation: 227

django choicefield filter in admin panel

by default django admin's list_filter provide all filters available in model choices. but apart from those I want one more filter, lets say it 'None' filter.

class Mymodel:
    char choice field (choices=(('1', 'txt1', '2', 'txt2')), null=True)

class MymodelAdmin(admin.ModelAdmin):
    ...
    list_filter = [..., choice_field, ...]
    ...

this will set three filter in admin panel(right hand side filters) , All, 'txt1', 'txt2'. right? I want one more filter 'None' if no value is assign from choices.

what I tried so far..

class ChoiceFieldFilter(admin.filters.ChoicesFieldListFilter):

    def __init__(self, *args, **kwargs):
        super(ChoiceFieldFilter, self).__init__(*args, **kwargs)

        self.lookup_val = [('', 'None')]

    def queryset(self, request, queryset):
        print self.lookup_val
        print  self.field.flatchoices
        if self.lookup_val == '':
            return queryset.filter(choice_field='')
        else:
            return queryset.filter(choice_field=self.lookup_val)

    def choices(self, cl):
        pass

and then in admin class

list_filter = [..., ('choice_field', ChoiceFieldFilter), ...]

but its not working, I'm unable to see None filter in django admin

Upvotes: 5

Views: 5910

Answers (2)

ВелоКастръ
ВелоКастръ

Reputation: 4453

By default the admin.AllValuesFieldListFilter return a value of a choice, not verbose name of the choice. So, for resolve it use the modified admin.AllValuesFieldListFilter.

class AllValuesChoicesFieldListFilter(admin.AllValuesFieldListFilter):

    def choices(self, changelist):
        yield {
            'selected': self.lookup_val is None and self.lookup_val_isnull is None,
            'query_string': changelist.get_query_string({}, [self.lookup_kwarg, self.lookup_kwarg_isnull]),
            'display': _('All'),
        }
        include_none = False

        # all choices for this field
        choices = dict(self.field.choices)

        for val in self.lookup_choices:
            if val is None:
                include_none = True
                continue
            val = smart_text(val)
            yield {
                'selected': self.lookup_val == val,
                'query_string': changelist.get_query_string({
                    self.lookup_kwarg: val,
                }, [self.lookup_kwarg_isnull]),

                # instead code, display title
                'display': choices[val],
            }
        if include_none:
            yield {
                'selected': bool(self.lookup_val_isnull),
                'query_string': changelist.get_query_string({
                    self.lookup_kwarg_isnull: 'True',
                }, [self.lookup_kwarg]),
                'display': self.empty_value_display,
            }

Usage:

list_filter = (
        ('country_origin', AllValuesChoicesFieldListFilter),
    )

Upvotes: 3

Nick
Nick

Reputation: 1194

You don't have to make your custom list filter. Just use django's AllValuesFieldListFilter

from django.contrib.admin.filters import AllValuesFieldListFilter
...
list_filter = [..., ('choice_field', AllValuesFieldListFilter)]
...

Upvotes: 6

Related Questions