[Fixed]-List filter by custom list display field in django admin


Unfortunately this is not possible. In django.admin.views, when collecting filter fields happens this:

if not isinstance(field, Field):
   field_path = field
   field = get_fields_from_path(self.model, field_path)[-1]

So, state is not a Field instance, but a function that returns string or None. Then as you can see, Django tries to add fields to list_filter anyway, assuming it is not a Field instance, but can be path to model field.
Eventually it adds state to list_filter, and then goes to django.db.models.options.Options to retrieve instance of field.

    # Retrieve field instance by name from cached or just-computed
    # field map.
    return self.fields_map[field_name]
except KeyError:
    raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))

As you see, Django can not see this field in model and throws an Exception. This Exception is handled by django.core.management.base.BaseCommand, that converts error message to "list_filter[0]' refers to 'state' which does not refer to a Field."


list_filter works on related models.

If model looks like that:

class Address(models.Model):
    owner = models.OneToOneField(Customer, models.CASCADE,
    state = models.CharField(max_length=20)

You can use address__state in ModelAdmin. For example:

class CustomerAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email', 'state')
    search_fields = ('first_name', 'last_name', 'email')
    list_filter = ('address__state', )

Note that list_display doesn’t work this way!


class CustomerAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'email', 'state')
list_filter = ('state',)
search_fields = ('first_name', 'last_name', 'email')

def state(self, obj):
    address = Address.objects.filter(owner=obj.id)
    if address:
        return address.state
return None

You should include list_filter if you want to filter


Leave a comment