Skip to Content
FeaturesModulesDjango AdminFilters

Filters Guide

Django Admin v2.0 supports a declarative FilterConfig API that maps directly to Unfold’s filter components — no boilerplate, no manual class definitions for common patterns.

Two Styles, One Field

list_filter accepts both the new declarative style and the classic raw style. Mix them freely — they resolve to the same Django format under the hood.

from django_cfg.modules.django_admin import AdminConfig, FilterConfig config = AdminConfig( model=Payment, list_filter=[ # Declarative — new FilterConfig(field='status', type='choices_dropdown'), FilterConfig(field='created_at', type='range_date'), FilterConfig(field='amount', type='range_numeric'), FilterConfig(field='user', type='autocomplete'), # Raw — still works 'currency', MyCustomFilter, ('is_test', BooleanRadioFilter), ], )

FilterConfig Reference

from django_cfg.modules.django_admin import FilterConfig FilterConfig( field='status', # Model field name type='choices_dropdown', # One of 17 FilterType values (see table below) title=None, # Custom sidebar label (SimpleListFilter types only) filter_class=None, # Raw filter class — bypasses type lookup )

FilterType values

typeUnfold classDjango baseUse case
choices_dropdownChoicesDropdownFilterFieldListFilterField with choices= — single select
choices_dropdown_multipleMultipleChoicesDropdownFilterFieldListFilterField with choices= — multi-select
choices_checkboxChoicesCheckboxFilterFieldListFilterField choices as checkboxes
choices_radioChoicesRadioFilterFieldListFilterField choices as radio buttons
booleanBooleanRadioFilterFieldListFilterBooleanField — Yes / No
related_dropdownRelatedDropdownFilterFieldListFilterForeignKey — single select
related_dropdown_multipleMultipleRelatedDropdownFilterFieldListFilterForeignKey — multi-select
related_checkboxRelatedCheckboxFilterFieldListFilterForeignKey — checkboxes
autocompleteAutocompleteSelectFilterFieldListFilterForeignKey with search input
autocomplete_multipleAutocompleteSelectMultipleFilterFieldListFilterSame — multi-select
range_numericRangeNumericFilterFieldListFilterNumeric from / to inputs
sliderSliderNumericFilterFieldListFilterNumeric slider (auto min/max)
range_dateRangeDateFilterFieldListFilterDateField from / to
range_datetimeRangeDateTimeFilterFieldListFilterDateTimeField from / to
textFieldTextFilterFieldListFilterText search (icontains)
dropdownDropdownFilterSimpleListFilterCustom queryset — dropdown UI
dropdown_multipleMultipleDropdownFilterSimpleListFilterCustom queryset — multi dropdown

FieldListFilter-based types are bound to a model field automatically. SimpleListFilter-based types (dropdown, dropdown_multiple) need you to subclass them and implement lookups() and queryset() — use filter_class for those.


Examples by Use Case

Status / Choice field

from django_cfg.modules.django_admin import AdminConfig, FilterConfig config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='status', type='choices_dropdown'), ], )

Works with any CharField / IntegerField that has choices= defined on the model.

ForeignKey — dropdown

config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='customer', type='related_dropdown'), FilterConfig(field='warehouse', type='related_dropdown'), ], )
config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='customer', type='autocomplete'), ], )

autocomplete and autocomplete_multiple require the related model’s admin to define search_fields. Without it Django raises AttributeError at runtime.

# Required: the related admin must have search_fields @admin.register(Customer) class CustomerAdmin(PydanticAdmin): config = AdminConfig( model=Customer, search_fields=['name', 'email'], # ← required ... )

Numeric range

config = AdminConfig( model=Transaction, list_filter=[ FilterConfig(field='amount', type='range_numeric'), ], )

Renders two inputs: From and To. Works with IntegerField, DecimalField, FloatField.

Numeric slider

config = AdminConfig( model=Product, list_filter=[ FilterConfig(field='price', type='slider'), ], )

Auto-calculates min/max from the queryset. Renders a drag handle slider.

Date range

config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='created_at', type='range_date'), FilterConfig(field='shipped_at', type='range_datetime'), ], )

Boolean field

config = AdminConfig( model=User, list_filter=[ FilterConfig(field='is_active', type='boolean'), FilterConfig(field='is_staff', type='boolean'), ], )

Renders horizontal Yes / No radio buttons.

Text search in sidebar

config = AdminConfig( model=Product, list_filter=[ FilterConfig(field='name', type='text'), ], )

Adds a text input filter using icontains lookup.

Multi-select checkboxes

config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='status', type='choices_checkbox'), FilterConfig(field='category', type='related_checkbox'), ], )

Custom filter class

For business-logic filters (custom queryset(), dynamic choices), pass the class directly via filter_class:

from django.contrib import admin class RecentOrdersFilter(admin.SimpleListFilter): title = 'time range' parameter_name = 'range' def lookups(self, request, model_admin): return [ ('24h', 'Last 24 hours'), ('7d', 'Last 7 days'), ('30d', 'Last 30 days'), ] def queryset(self, request, queryset): from datetime import timedelta from django.utils import timezone now = timezone.now() if self.value() == '24h': return queryset.filter(created_at__gte=now - timedelta(hours=24)) if self.value() == '7d': return queryset.filter(created_at__gte=now - timedelta(days=7)) if self.value() == '30d': return queryset.filter(created_at__gte=now - timedelta(days=30)) return queryset config = AdminConfig( model=Order, list_filter=[ FilterConfig(field='range', filter_class=RecentOrdersFilter), # Or just pass the class directly — both work: # RecentOrdersFilter, ], )

When filter_class is a SimpleListFilter subclass it is returned as-is. When it is a FieldListFilter subclass it is returned as ('field', FilterClass).


Simple string filters

Django auto-detects the filter type from the model field:

config = AdminConfig( model=Order, list_filter=['status', 'created_at', 'is_active', 'customer'], )
Field typeAuto-detected filter
BooleanFieldYes / No / All
CharField with choicesChoice filter
ForeignKeyRelated object list
DateField / DateTimeFieldDate drill-down
IntegerFieldExact value

Facet counts

Show the number of matching records next to each filter option:

config = AdminConfig( model=Order, show_facets=True, list_filter=[ FilterConfig(field='status', type='choices_dropdown'), ], )

Requires Django 5.0+ and SHOW_FACETS = ShowFacets.ALLOW in UNFOLD settings or django.contrib.admin.ShowFacets.ALWAYS in AdminSite.


Date hierarchy

For date-based drill-down navigation above the list:

config = AdminConfig( model=Order, date_hierarchy='created_at', list_filter=[ FilterConfig(field='status', type='choices_dropdown'), ], )

Complete example

from django.contrib import admin from django_cfg.modules.django_admin import ( AdminConfig, BadgeField, CurrencyField, DateTimeField, FilterConfig, UserField, Icons, ) from django_cfg.modules.django_admin.base import PydanticAdmin config = AdminConfig( model=Payment, list_display=['id', 'user', 'amount', 'status', 'created_at'], display_fields=[ BadgeField( name='status', label_map={ 'pending': 'warning', 'processing': 'info', 'completed': 'success', 'failed': 'danger', }, ), UserField(name='user', header=True), CurrencyField(name='amount', currency='USD', precision=2), DateTimeField(name='created_at', show_relative=True), ], list_filter=[ FilterConfig(field='status', type='choices_dropdown'), FilterConfig(field='created_at', type='range_date'), FilterConfig(field='amount', type='range_numeric'), FilterConfig(field='user', type='autocomplete'), 'currency', ], show_facets=True, date_hierarchy='created_at', search_fields=['id', 'user__email'], select_related=['user', 'currency'], ordering=['-created_at'], ) @admin.register(Payment) class PaymentAdmin(PydanticAdmin): config = config

Performance tips

Index filtered fields — every field in list_filter should have a DB index:

class Payment(models.Model): status = models.CharField(choices=STATUS_CHOICES, db_index=True) created_at = models.DateTimeField(db_index=True) amount = models.DecimalField(...)

Prefer autocomplete over dropdown for large FK tables:

# ❌ Loads all customers into the dropdown FilterConfig(field='customer', type='related_dropdown') # ✅ Lazy search — fast even with millions of records FilterConfig(field='customer', type='autocomplete')

Use select_related to avoid N+1 on FK filter options:

config = AdminConfig( model=Order, select_related=['customer', 'warehouse'], list_filter=[ FilterConfig(field='customer', type='related_dropdown'), ], )

Next Steps

TAGS: filters, list_filter, FilterConfig, FilterType, dropdown, autocomplete, range, unfold

Last updated on