Vijay
Vijay

Reputation: 974

list filter by custom list display field in django admin

I have following model admin. I'm displaying custom field in list view.

class CustomerAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email', 'state')
    search_fields = ('first_name', 'last_name', 'email')
    list_filter = ('state',)
    def state(self, obj):
        address = Address.objects.filter(owner=obj.id)
        if address:
            return address.state
    return None

I tried above but it gives an error "list_filter[0]' refers to 'state' which does not refer to a Field." So I want filter records by state. So how I can do this in django 1.5?

Upvotes: 19

Views: 4014

Answers (3)

Vitalii Korniichuk
Vitalii Korniichuk

Reputation: 33

list_filter works on related models.

If model looks like that:

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

You can use address__state in ModelAdmin. For example:

@admin.register(Customer)
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!

Upvotes: 1

Nikita Sysoev
Nikita Sysoev

Reputation: 36

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.

try:
    # 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."

Upvotes: 0

varad
varad

Reputation: 8029

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

Upvotes: -4

Related Questions