ModelAdmin.list_filter  
Set list_filter to activate filters in the right sidebar of the change list page of the admin, as illustrated in the following screenshot:  list_filter should be a list or tuple of elements, where each element should be of one of the following types:  
a field name, where the specified field should be either a BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey or ManyToManyField, for example: class PersonAdmin(admin.ModelAdmin):
    list_filter = ('is_staff', 'company')
 Field names in list_filter can also span relations using the __ lookup, for example: class PersonAdmin(admin.UserAdmin):
    list_filter = ('company__name',)
  
a class inheriting from django.contrib.admin.SimpleListFilter, which you need to provide the title and parameter_name attributes to and override the lookups and queryset methods, e.g.: from datetime import date

from django.contrib import admin
from django.utils.translation import gettext_lazy as _

class DecadeBornListFilter(admin.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(admin.ModelAdmin):
    list_filter = (DecadeBornListFilter,)
  Note As a convenience, the HttpRequest object is passed to the lookups and queryset methods, for example: class AuthDecadeBornListFilter(DecadeBornListFilter):

    def lookups(self, request, model_admin):
        if request.user.is_superuser:
            return super().lookups(request, model_admin)

    def queryset(self, request, queryset):
        if request.user.is_superuser:
            return super().queryset(request, queryset)
 Also as a convenience, the ModelAdmin object is passed to the lookups method, for example if you want to base the lookups on the available data: class AdvancedDecadeBornListFilter(DecadeBornListFilter):

    def lookups(self, request, model_admin):
        """
        Only show the lookups if there actually is
        anyone born in the corresponding decades.
        """
        qs = model_admin.get_queryset(request)
        if qs.filter(birthday__gte=date(1980, 1, 1),
                      birthday__lte=date(1989, 12, 31)).exists():
            yield ('80s', _('in the eighties'))
        if qs.filter(birthday__gte=date(1990, 1, 1),
                      birthday__lte=date(1999, 12, 31)).exists():
            yield ('90s', _('in the nineties'))
   
a tuple, where the first element is a field name and the second element is a class inheriting from django.contrib.admin.FieldListFilter, for example: class PersonAdmin(admin.ModelAdmin):
    list_filter = (
        ('is_staff', admin.BooleanFieldListFilter),
    )
 You can limit the choices of a related model to the objects involved in that relation using RelatedOnlyFieldListFilter: class BookAdmin(admin.ModelAdmin):
    list_filter = (
        ('author', admin.RelatedOnlyFieldListFilter),
    )
 Assuming author is a ForeignKey to a User model, this will limit the list_filter choices to the users who have written a book instead of listing all users. You can filter empty values using EmptyFieldListFilter, which can filter on both empty strings and nulls, depending on what the field allows to store: class BookAdmin(admin.ModelAdmin):
    list_filter = (
        ('title', admin.EmptyFieldListFilter),
    )
  Note The FieldListFilter API is considered internal and might be changed.   Note The GenericForeignKey field is not supported.    List filter’s typically appear only if the filter has more than one choice. A filter’s has_output() method controls whether or not it appears. It is possible to specify a custom template for rendering a list filter: class FilterWithCustomTemplate(admin.SimpleListFilter):
    template = "custom_template.html"
 See the default template provided by Django (admin/filter.html) for a concrete example.