Overview
Checkbox and radio filters provide visual selection interfaces that display all available options at once. Checkboxes allow multiple selections, while radio buttons enforce single selection.
These filters are ideal when you have 2-10 options that users need to see simultaneously.
Available Choice Filters
RadioFilter Single selection with custom options
CheckboxFilter Multiple selection with custom options
ChoicesRadioFilter Radio buttons for model choice fields
ChoicesCheckboxFilter Checkboxes for model choice fields
BooleanRadioFilter Yes/No/All filter for boolean fields
RelatedCheckboxFilter Multiple selection for related objects
AllValuesCheckboxFilter Checkboxes for all unique field values
RadioFilter
Single selection using radio buttons.
Basic Usage
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import RadioFilter
from .models import Product
class StatusRadioFilter ( RadioFilter ):
title = "Status"
parameter_name = "status"
def lookups ( self , request , model_admin ):
return (
( "draft" , "Draft" ),
( "published" , "Published" ),
( "archived" , "Archived" ),
)
def queryset ( self , request , queryset ):
if self .value():
return queryset.filter( status = self .value())
return queryset
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_display = [ "name" , "status" ]
list_filter = [StatusRadioFilter]
Removing “All” Option
By default, radio filters include an “All” option:
class StatusRadioFilter ( RadioFilter ):
title = "Status"
parameter_name = "status"
all_option = None # Remove "All" option
def lookups ( self , request , model_admin ):
return (
( "active" , "Active" ),
( "inactive" , "Inactive" ),
)
Custom “All” Label
class StatusRadioFilter ( RadioFilter ):
title = "Status"
parameter_name = "status"
all_option = [ "" , "Any Status" ] # Custom label
def lookups ( self , request , model_admin ):
return (
( "active" , "Active" ),
( "inactive" , "Inactive" ),
)
CheckboxFilter
Multiple selection using checkboxes.
from unfold.contrib.filters.admin import CheckboxFilter
class TagsCheckboxFilter ( CheckboxFilter ):
title = "Tags"
parameter_name = "tags"
def lookups ( self , request , model_admin ):
return (
( "featured" , "Featured" ),
( "new" , "New Arrival" ),
( "sale" , "On Sale" ),
( "trending" , "Trending" ),
)
def queryset ( self , request , queryset ):
# value() returns a list of selected items
selected_values = self .value()
if selected_values:
return queryset.filter( tags__name__in = selected_values)
return queryset
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_filter = [TagsCheckboxFilter]
With CheckboxFilter, the value() method returns a list of all selected values, allowing for multiple selections.
ChoicesRadioFilter
Automatic radio filter for model fields with choices.
Model with Choices
from django.db import models
class Product ( models . Model ):
class Priority ( models . TextChoices ):
LOW = "low" , "Low Priority"
MEDIUM = "medium" , "Medium Priority"
HIGH = "high" , "High Priority"
URGENT = "urgent" , "Urgent"
name = models.CharField( max_length = 200 )
priority = models.CharField(
max_length = 20 ,
choices = Priority.choices,
default = Priority. MEDIUM ,
)
Apply Filter
from unfold.contrib.filters.admin import ChoicesRadioFilter
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_display = [ "name" , "priority" ]
list_filter = [
( "priority" , ChoicesRadioFilter),
]
The filter automatically uses the choices defined in your model. No need to specify lookups manually.
ChoicesCheckboxFilter
Multiple selection for choice fields.
class Article ( models . Model ):
class Status ( models . TextChoices ):
DRAFT = "draft" , "Draft"
REVIEW = "review" , "In Review"
PUBLISHED = "published" , "Published"
ARCHIVED = "archived" , "Archived"
status = models.CharField(
max_length = 20 ,
choices = Status.choices,
)
from unfold.contrib.filters.admin import ChoicesCheckboxFilter
@admin.register (Article)
class ArticleAdmin ( ModelAdmin ):
list_filter = [
( "status" , ChoicesCheckboxFilter),
]
BooleanRadioFilter
Specialized filter for boolean fields with Yes/No/All options.
Basic Usage
class Product ( models . Model ):
name = models.CharField( max_length = 200 )
is_active = models.BooleanField( default = True )
is_featured = models.BooleanField( default = False )
from unfold.contrib.filters.admin import BooleanRadioFilter
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_display = [ "name" , "is_active" , "is_featured" ]
list_filter = [
( "is_active" , BooleanRadioFilter),
( "is_featured" , BooleanRadioFilter),
]
This creates three radio options:
All : Show all records
Yes : Show only True values
No : Show only False values
Horizontal Layout
The filter displays options horizontally for better space usage:
# Renders as: ○ All ○ Yes ○ No
Multiple selection for foreign key relationships.
Basic Example
class Category ( models . Model ):
name = models.CharField( max_length = 100 )
def __str__ ( self ):
return self .name
class Product ( models . Model ):
name = models.CharField( max_length = 200 )
category = models.ForeignKey(Category, on_delete = models. CASCADE )
from unfold.contrib.filters.admin import RelatedCheckboxFilter
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_display = [ "name" , "category" ]
list_filter = [
( "category" , RelatedCheckboxFilter),
]
Users can select multiple categories to filter products. The filter uses OR logic by default.
class Tag ( models . Model ):
name = models.CharField( max_length = 50 )
def __str__ ( self ):
return self .name
class Article ( models . Model ):
title = models.CharField( max_length = 200 )
tags = models.ManyToManyField(Tag)
@admin.register (Article)
class ArticleAdmin ( ModelAdmin ):
list_filter = [
( "tags" , RelatedCheckboxFilter),
]
AllValuesCheckboxFilter
Automatically create checkboxes for all unique values in a field.
class Product ( models . Model ):
name = models.CharField( max_length = 200 )
manufacturer = models.CharField( max_length = 100 )
from unfold.contrib.filters.admin import AllValuesCheckboxFilter
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_filter = [
( "manufacturer" , AllValuesCheckboxFilter),
]
This filter queries the database to find all unique values. Use with caution on fields with many distinct values.
Faceted Counts
All checkbox and radio filters support showing counts:
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import ChoicesRadioFilter
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
show_facets = admin.ShowFacets. ALWAYS
list_filter = [
( "status" , ChoicesRadioFilter), # Shows "Published (42)"
]
Advanced Customization
Dynamic Lookups
from django.db.models import Count
class PopularCategoriesFilter ( CheckboxFilter ):
title = "Popular Categories"
parameter_name = "popular_category"
def lookups ( self , request , model_admin ):
# Only show categories with 10+ products
categories = Category.objects.annotate(
product_count = Count( 'product' )
).filter( product_count__gte = 10 )
return [(cat.id, cat.name) for cat in categories]
def queryset ( self , request , queryset ):
if self .value():
return queryset.filter( category_id__in = self .value())
return queryset
Custom Ordering
class OrderedStatusFilter ( RadioFilter ):
title = "Status"
parameter_name = "status"
def lookups ( self , request , model_admin ):
# Custom order: most important statuses first
return (
( "urgent" , "🔴 Urgent" ),
( "high" , "🟡 High Priority" ),
( "medium" , "🟢 Medium Priority" ),
( "low" , "⚪ Low Priority" ),
)
Conditional Display
class ConditionalFilter ( CheckboxFilter ):
title = "Tags"
parameter_name = "tags"
def lookups ( self , request , model_admin ):
# Show different options based on user permissions
if request.user.is_superuser:
return (
( "public" , "Public" ),
( "private" , "Private" ),
( "internal" , "Internal" ),
)
else :
return (
( "public" , "Public" ),
)
def queryset ( self , request , queryset ):
if self .value():
return queryset.filter( visibility__in = self .value())
return queryset
Combining Multiple Filters
from unfold.contrib.filters.admin import (
BooleanRadioFilter,
CheckboxFilter,
RelatedCheckboxFilter,
)
class TagFilter ( CheckboxFilter ):
title = "Tags"
parameter_name = "tags"
def lookups ( self , request , model_admin ):
return (
( "featured" , "Featured" ),
( "new" , "New" ),
( "sale" , "On Sale" ),
)
def queryset ( self , request , queryset ):
if self .value():
return queryset.filter( tags__name__in = self .value())
return queryset
@admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_filter = [
( "is_active" , BooleanRadioFilter),
( "category" , RelatedCheckboxFilter),
TagFilter,
]
from unfold.contrib.filters.forms import CheckboxForm
class StyledCheckboxForm ( CheckboxForm ):
def __init__ ( self , * args , ** kwargs ):
super (). __init__ ( * args, ** kwargs)
# Add custom styling or attributes
for field in self .fields.values():
field.widget.attrs.update({
'class' : 'custom-checkbox' ,
})
class StyledCheckboxFilter ( CheckboxFilter ):
form_class = StyledCheckboxForm
title = "Categories"
parameter_name = "category"
For filters with many options, consider limiting display: class LimitedCheckboxFilter ( CheckboxFilter ):
MAX_OPTIONS = 20
def lookups ( self , request , model_admin ):
categories = Category.objects.all()[: self . MAX_OPTIONS ]
return [(cat.id, cat.name) for cat in categories]
Use select_related() or prefetch_related(): @admin.register (Product)
class ProductAdmin ( ModelAdmin ):
list_filter = [( "category" , RelatedCheckboxFilter)]
def get_queryset ( self , request ):
return super ().get_queryset(request).select_related( 'category' )
Cache expensive lookup queries: from django.core.cache import cache
class CachedCheckboxFilter ( CheckboxFilter ):
def lookups ( self , request , model_admin ):
cache_key = f "filter_lookups_ { self .parameter_name } "
lookups = cache.get(cache_key)
if lookups is None :
lookups = self ._compute_lookups()
cache.set(cache_key, lookups, 300 ) # 5 minutes
return lookups
def _compute_lookups ( self ):
# Expensive query here
return Category.objects.all().values_list( 'id' , 'name' )
User Experience Guidelines
Choose between radio and checkbox
Radio : Single selection, mutually exclusive options (status, priority)
Checkbox : Multiple selection, combinable options (tags, categories)
Limit visible options
Keep options between 2-10 for best UX. For more options, consider dropdown or autocomplete filters.
Use clear labels
Make option labels descriptive and concise: ( "active" , "Active" ) # Good
( "1" , "Status 1" ) # Bad
Order logically
Order options by:
Frequency of use
Importance
Alphabetically
Custom business logic
API Reference
RadioFilter
Display name for the filter
all_option
list[str] | None
default: "[\"\", \"All\"]"
Option to clear filter. Set to None to remove.
CheckboxFilter
Display name for the filter
Checkbox filters don’t have an “All” option
form_class
type
default: "CheckboxForm"
Form class for rendering
BooleanRadioFilter
all_option
list[str]
default: "[\"\", \"All\"]"
Option to show all records
form_class
type
default: "HorizontalRadioForm"
Uses horizontal layout by default
Best Practices
When to use radio filters
Status fields with 3-5 states
Priority levels
Boolean-like fields with more than 2 options
When only one choice makes sense
When to use checkbox filters
Tags or categories
Features or attributes
Any field where multiple selections are valid
Filtering by multiple related objects
More than 10 options (use dropdown or autocomplete)
Very long option labels (use dropdown)
Dynamic data with frequently changing options
Fields with thousands of unique values
Next Steps
Dropdown Filters Learn about dropdown alternatives for more options
Filter Overview Return to filters overview