Creating Custom Filters for list_filter in Django Admin

DjangoDjango Admin

Django Problem Overview


I would like to make custom filters for django admin instead of the normal 'is_staff' and 'is_superuser'. I have read this list_filter in Django docs. Custom Filters work in this way:

from datetime import date

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class DecadeBornListFilter(SimpleListFilter):
    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = _('decade born')

    # Parameter for the filter that will be used in the URL query.
    parameter_name = 'decade'

    def lookups(self, request, model_admin):
        """
        Returns a list of tuples. The first element in each
        tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        """
        return (
            ('80s', _('in the eighties')),
            ('90s', _('in the nineties')),
        )

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        # Compare the requested value (either '80s' or '90s')
        # to decide how to filter the queryset.
        if self.value() == '80s':
            return queryset.filter(birthday__gte=date(1980, 1, 1),
                                    birthday__lte=date(1989, 12, 31))
        if self.value() == '90s':
            return queryset.filter(birthday__gte=date(1990, 1, 1),
                                    birthday__lte=date(1999, 12, 31))

class PersonAdmin(ModelAdmin):
    list_filter = (DecadeBornListFilter,)

But i have already made custom functions for list_display like this:

def Student_Country(self, obj):
    return '%s' % obj.country
Student_Country.short_description = 'Student-Country'

Is it possible i could use the custom functions for list_display in list_filter instead of writing a new custom function for list_filter? Any suggestions or improvements are welcome.. Need some guidance on this... Thanks...

Django Solutions


Solution 1 - Django

You can indeed add custom filters to admin filters by extending SimpleListFilter. For instance, if you want to add a continent filter for 'Africa' to the country admin filter used above, you can do the following:

In admin.py:

from django.contrib.admin import SimpleListFilter

class CountryFilter(SimpleListFilter):
    title = 'country' # or use _('country') for translated title
    parameter_name = 'country'

    def lookups(self, request, model_admin):
        countries = set([c.country for c in model_admin.model.objects.all()])
        return [(c.id, c.name) for c in countries] + [
          ('AFRICA', 'AFRICA - ALL')]

    def queryset(self, request, queryset):
        if self.value() == 'AFRICA':
            return queryset.filter(country__continent='Africa')
        if self.value():
            return queryset.filter(country__id__exact=self.value())

class CityAdmin(ModelAdmin):
    list_filter = (CountryFilter,)

Solution 2 - Django

Your list_display ,method returns a string, but if I understand correctly, what you want to do is add a filter which allows selection of countries of students, correct?

For this simple relation filter, and in fact for the "Student-Country" list display column as well, you don't need to create a custom filter class, nor a custom list display method; this would suffice:

class MyAdmin(admin.ModelAdmin):
    list_display = ('country', )
    list_filter = ('country', )

The way django does list_filter, as explained in the docs, is first by automatically matching fields you provide to pre-built filter classes; these filters include CharField and ForeignKey.

list_display similarly automates the population of the changelist column using the field passed by retrieving the related objects and returning the unicode value of these (same as in the method you provided above).

Solution 3 - Django

In addition to Rick Westera answer, here is the Django Docs for this situation

>ModelAdmin.list_filter
>Set list_filter to activate filters in the right sidebar of the change list page of the admin
>list_filter should be a list or tuple of elements

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlakshmenView Question on Stackoverflow
Solution 1 - DjangoRick WesteraView Answer on Stackoverflow
Solution 2 - DjangotutuDajujuView Answer on Stackoverflow
Solution 3 - DjangohasherView Answer on Stackoverflow