Filtering Django Admin by Null/Is Not Null
Since Django 1.4 brings some changes to filters, I thought I save someone the time I just spent modifying the code from Cerin's accepted answer to work with Django 1.4 rc1.
I have a model that has TimeField(null=True) named "started" and I wanted to filter for null and non-null values, so it's prety much the same problem as OP.
So, here is what worked for me...
Defined (actually included) these in admin.py:
from django.contrib.admin.filters import SimpleListFilterclass NullFilterSpec(SimpleListFilter): title = u'' parameter_name = u'' def lookups(self, request, model_admin): return ( ('1', _('Has value'), ), ('0', _('None'), ), ) def queryset(self, request, queryset): kwargs = { '%s'%self.parameter_name : None, } if self.value() == '0': return queryset.filter(**kwargs) if self.value() == '1': return queryset.exclude(**kwargs) return querysetclass StartNullFilterSpec(NullFilterSpec): title = u'Started' parameter_name = u'started'
Than just used them in ModelAdmin:
class SomeModelAdmin(admin.ModelAdmin): list_filter = (StartNullFilterSpec, )
After Django 3.1 you can use EmptyFieldListFilter:
class MyAdmin(admin.ModelAdmin): list_filter = ( ("model_field", admin.EmptyFieldListFilter), )
I have a simpler version of frnhr's answer, which actually filters on __isnull
condition.(Django 1.4+):
from django.contrib.admin import SimpleListFilterclass NullListFilter(SimpleListFilter): def lookups(self, request, model_admin): return ( ('1', 'Null', ), ('0', '!= Null', ), ) def queryset(self, request, queryset): if self.value() in ('0', '1'): kwargs = { '{0}__isnull'.format(self.parameter_name) : self.value() == '1' } return queryset.filter(**kwargs) return queryset
Then also:
class StartNullListFilter(NullListFilter): title = u'Started' parameter_name = u'started'
and finally:
class SomeModelAdmin(admin.ModelAdmin): list_filter = (StartNullListFilter, )
I personally don't like to trash my admin.py
with dozens of classes, so I came up with such a helper function:
def null_filter(field, title_=None): class NullListFieldFilter(NullListFilter): parameter_name = field title = title_ or parameter_name return NullListFieldFilter
Which I can later apply as in:
class OtherModelAdmin(admin.ModelAdmin): list_filter = (null_filter('somefield'), null_filter('ugly_field', _('Beautiful Name')), )