Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering Django Admin by Null/Is Not Null

I have a simple Django model like:

class Person(models.Model):
    referrer = models.ForeignKey('self', null=True)
    ...

In this model's ModelAdmin, how would I allow it to be filtered by whether or not referrer is null? By default, adding referrer to list_filter causes a dropdown to be shown that lists every person record, which may be in the hundreds of thousands, effectively preventing the page from loading. Even if it loads, I still can't filter by the criteria I want.

i.e. How would I modify this so that the dropdown only lists "All", "Null", or "Not Null" choices?

I've seen some posts that claim to accomplish something similar using custom FilterSpec subclasses, but none of them explain how to use them. The few I've seen appear to apply to all fields in all models, which I wouldn't want. Moreover, there's zero documentation for FilterSpec, which makes me nervous, because I don't want to invest in a lot of custom code tied to some transient internal class that might disappear by the next release.

like image 561
Cerin Avatar asked Oct 07 '11 19:10

Cerin


People also ask

How check field is null in Django?

null=True will make the field accept NULL values. Blank values for Django field types such as DateTimeField or ForeignKey will be stored as NULL in the database.

What is Django filter?

Django-filter is a generic, reusable application to alleviate writing some of the more mundane bits of view code. Specifically, it allows users to filter down a queryset based on a model's fields, displaying the form to let them do this.


2 Answers

After Django 3.1 you can use EmptyFieldListFilter:

class MyAdmin(admin.ModelAdmin):
    list_filter =  (
        ("model_field", admin.EmptyFieldListFilter),
    )
like image 112
Calzzetta Avatar answered Oct 03 '22 07:10

Calzzetta


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 SimpleListFilter

class 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 queryset



class StartNullFilterSpec(NullFilterSpec):
    title = u'Started'
    parameter_name = u'started'

Than just used them in ModelAdmin:

class SomeModelAdmin(admin.ModelAdmin):
    list_filter =  (StartNullFilterSpec, )
like image 41
frnhr Avatar answered Oct 03 '22 07:10

frnhr