Skip to main content

Overview

Autocomplete filters provide a search-enabled filtering interface that loads options dynamically via AJAX. This makes them perfect for filtering by fields with large datasets (hundreds or thousands of options) where standard dropdowns would be impractical.
Autocomplete filters require the related model to have an admin class registered with search_fields defined.

Available Autocomplete Filters

AutocompleteSelectFilter

Single selection with search for related fields

AutocompleteSelectMultipleFilter

Multiple selection with search for related fields

AutocompleteSelectFilter

Filter by a single related object with search capabilities.

Basic Setup

1

Configure the related model admin

The related model must have search_fields defined:
admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from .models import Author

@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name", "email"]
2

Add autocomplete filter to your model

admin.py
from unfold.contrib.filters.admin import AutocompleteSelectFilter
from .models import Book

@admin.register(Book)
class BookAdmin(ModelAdmin):
    list_filter = [
        ("author", AutocompleteSelectFilter),
    ]

Complete Example

models.py
from django.db import models


class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

    def __str__(self):
        return f"{self.first_name} {self.last_name}"


class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateField()

    def __str__(self):
        return self.title
admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import AutocompleteSelectFilter

from .models import Author, Book


@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name", "email"]
    list_display = ["first_name", "last_name", "email"]


@admin.register(Book)
class BookAdmin(ModelAdmin):
    list_display = ["title", "author", "published_date"]
    list_filter = [
        ("author", AutocompleteSelectFilter),
    ]
Users can now type in the filter to search authors by first name, last name, or email.

AutocompleteSelectMultipleFilter

Filter by multiple related objects with search.
models.py
class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)

    def __str__(self):
        return self.name


class Article(models.Model):
    title = models.CharField(max_length=200)
    tags = models.ManyToManyField(Tag)
    published = models.BooleanField(default=False)
admin.py
from unfold.contrib.filters.admin import AutocompleteSelectMultipleFilter


@admin.register(Tag)
class TagAdmin(ModelAdmin):
    search_fields = ["name"]


@admin.register(Article)
class ArticleAdmin(ModelAdmin):
    list_display = ["title", "published"]
    list_filter = [
        ("tags", AutocompleteSelectMultipleFilter),
    ]
Users can select multiple tags to filter articles. The filter uses an AND logic by default (articles must have all selected tags).

Search Configuration

Use __icontains or __istartswith lookups:
admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = [
        "first_name__icontains",
        "last_name__icontains",
    ]
Search across relationships:
admin.py
@admin.register(Book)
class BookAdmin(ModelAdmin):
    search_fields = [
        "title",
        "author__first_name",  # Search by author's first name
        "author__last_name",    # Search by author's last name
    ]
    list_filter = [
        ("author", AutocompleteSelectFilter),
    ]

Customize Search Terms

admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name", "email"]

    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super().get_search_results(
            request, queryset, search_term
        )
        
        # Add custom search logic
        if search_term:
            # Example: Search by full name
            queryset |= self.model.objects.filter(
                first_name__icontains=search_term.split()[0] if search_term else ""
            )
        
        return queryset, use_distinct

Advanced Configuration

Minimum Search Length

You can configure minimum characters required before search triggers:
admin.py
from unfold.contrib.filters.admin import AutocompleteSelectFilter


class CustomAutocompleteFilter(AutocompleteSelectFilter):
    # Customize form to set minimum input length
    class Media:
        js = ('admin/js/custom-autocomplete.js',)

Custom Empty Label

admin.py
class CustomAutocompleteFilter(AutocompleteSelectFilter):
    def choices(self, changelist):
        for choice in super().choices(changelist):
            # Customize the form
            form = choice['form']
            # Add custom empty label or placeholder
            yield choice

Limit Results

Control the number of autocomplete results:
admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name"]
    
    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super().get_search_results(
            request, queryset, search_term
        )
        # Limit to 10 results
        return queryset[:10], use_distinct

Filtering ManyToManyField

For many-to-many relationships:
models.py
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)
    categories = models.ManyToManyField(Category)
admin.py
from unfold.contrib.filters.admin import AutocompleteSelectMultipleFilter


@admin.register(Category)
class CategoryAdmin(ModelAdmin):
    search_fields = ["name"]


@admin.register(Product)
class ProductAdmin(ModelAdmin):
    list_filter = [
        ("categories", AutocompleteSelectMultipleFilter),
    ]

With Faceted Counts

Autocomplete filters support faceted counts, but they only show after a selection is made (not during search).
admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import AutocompleteSelectFilter


@admin.register(Book)
class BookAdmin(ModelAdmin):
    show_facets = admin.ShowFacets.ALWAYS
    list_filter = [
        ("author", AutocompleteSelectFilter),
    ]

Permissions

Restrict Autocomplete Access

Control who can see autocomplete results:
admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name"]

    def has_view_permission(self, request, obj=None):
        # Only staff with view permission can search
        return request.user.has_perm('myapp.view_author')

Field-Level Permissions

admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name", "email"]

    def get_search_fields(self, request):
        # Hide email from search for non-superusers
        if request.user.is_superuser:
            return self.search_fields
        return ["first_name", "last_name"]

Performance Optimization

Add indexes to fields used in search_fields:
models.py
class Author(models.Model):
    first_name = models.CharField(max_length=100, db_index=True)
    last_name = models.CharField(max_length=100, db_index=True)
    email = models.EmailField(unique=True)  # Already indexed
Use select_related() and prefetch_related():
admin.py
@admin.register(Book)
class BookAdmin(ModelAdmin):
    list_filter = [("author", AutocompleteSelectFilter)]

    def get_queryset(self, request):
        return super().get_queryset(request).select_related('author')

Troubleshooting

Problem: Filter shows but autocomplete doesn’t trigger.Solution: Ensure the related model admin has search_fields defined:
admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    search_fields = ["first_name", "last_name"]  # Required!
Problem: Search returns no results even though data exists.Solution: Check that:
  1. search_fields contains the correct field names
  2. Fields are searchable (CharField, TextField, etc.)
  3. User has permission to view the related model
  4. Database contains matching records
Problem: Users get permission errors when using autocomplete.Solution: Ensure users have view permission for the related model:
admin.py
@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    def has_view_permission(self, request, obj=None):
        return request.user.has_perm('myapp.view_author')

API Reference

AutocompleteSelectFilter

field
Field
required
The model field to filter on (passed automatically in tuple format)
form_class
type
default:"AutocompleteDropdownForm"
Form class used for rendering the autocomplete widget
template
str
default:"\"unfold/filters/filters_field.html\""
Template used to render the filter

Requirements

The related model must have:
  • An admin class registered
  • search_fields defined
  • View permissions for the user

Best Practices

1

Use for large datasets

Autocomplete filters are ideal when you have >50 options. For fewer options, consider dropdown filters.
2

Optimize search fields

  • Index searchable fields in the database
  • Use specific field lookups (__istartswith vs __icontains)
  • Limit the number of fields in search_fields
3

Provide clear __str__ methods

Ensure related models have descriptive __str__ methods:
def __str__(self):
    return f"{self.first_name} {self.last_name} ({self.email})"

Next Steps

Dropdown Filters

Learn about standard dropdown filters for smaller datasets

Text Filters

Explore free-text search filters

Build docs developers (and LLMs) love