Skip to main content

PyPI version Tests Ruff

Django Admin Autocomplete Filters

Maintained continuation of the original project by Farhan Khan

This fork modernizes packaging (PEP 621), adds CI, and supports Django 4.2–6.1 and Python 3.10+.

A simple Django app to render list filters in django admin using an autocomplete widget. This app is heavily inspired by dal-admin-filters.

Overview:

Django comes preshipped with an admin panel which is a great utility to create quick CRUD's.

Version 2.0 came with a much needed autocomplete_fields property which uses a select2 widget to load the options asynchronously. We leverage this in django-admin-list-filter.

Requirements:

  • Django >= 4.2, < 6.2
  • Python >= 3.10

Supported Versions

  • Python: 3.10, 3.11, 3.12, 3.13, 3.14
  • Django: 4.2, 5.0, 5.1, 5.2, 6.0, 6.1 (Django 6.x requires Python 3.12+)

See the CI badge for the full matrix.

Features:

Installation:

You can install it via pip or poetry. To get the latest version clone this repo.

pip install django-admin-autocomplete-filters

or

poetry add django-admin-autocomplete-filters@latest

Add admin_auto_filters to your INSTALLED_APPS inside settings.py of your project.

Breaking Changes compared to original project:

  • CustomSearchView registration (Django 4.2+): pass the admin site instead of a model admin instance. See examples below.
    • Before: CustomSearchView.as_view(model_admin=self)
    • Now: CustomSearchView.as_view(admin_site=self.admin_site)
    • Rationale: the view uses Django’s process_request() to infer the target model admin from query params and performs core permission/validation checks. The admin site wrapper (self.admin_site.admin_view(...)) continues to enforce staff/CSRF safeguards.

Usage:

Let's say we have following models:

from django.db import models

class Artist(models.Model):
    name = models.CharField(max_length=128)

class Album(models.Model):
    name = models.CharField(max_length=64)
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    cover = models.CharField(max_length=256, null=True, default=None)

And you would like to filter results in AlbumAdmin on the basis of artist. You need to define search fields in Artist and then define filter like this:

from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilter


class ArtistFilter(AutocompleteFilter):
    title = 'Artist' # display title
    field_name = 'artist' # name of the foreign key field


class ArtistAdmin(admin.ModelAdmin):
    search_fields = ['name'] # this is required for django's autocomplete functionality
    # ...


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [ArtistFilter]
    # ...

After following these steps you may see the filter as:

Release Process

  • Bump admin_auto_filters.__version__ and update CHANGELOG.md.
  • Ensure CI is green on main.
  • Create a tag vX.Y.Z and push; the GitHub Actions workflow will build and publish to PyPI via trusted publishing.

Contributing

See CONTRIBUTING.md for local setup, linting, typing, tests, and pre-commit hooks.

You can also register your custom view instead of using Django admin's search_results to control the results in the autocomplete. For this you will need to create your custom view and register the URL in your admin class as shown below: In your views.py/admin.py/'filters.py':

from admin_auto_filters.views import AutocompleteJsonView
from django.contrib import admin
from django.urls import path

from django.shortcuts import reverse
from admin_auto_filters.filters import AutocompleteFilter


class ArtistFilter(AutocompleteFilter):
    title = 'Artist'
    field_name = 'artist'

    def get_autocomplete_url(self, request, model_admin):
        return reverse('admin:custom_search')


class CustomSearchView(AutocompleteJsonView):
    def get_queryset(self):
        """
           your custom logic goes here.
        """
        queryset = super().get_queryset()
        queryset = queryset.order_by('name')
        return queryset


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [
        ArtistFilter,
    ]

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path(
            'custom_search/', self.admin_site.admin_view(CustomSearchView.as_view(admin_site=self.admin_site)), name='custom_search'
            ),
        ]
        return custom_urls + urls

Shortcut for creating filters:

It's also possible to use the AutocompleteFilterFactory shortcut to create filters on the fly, as shown below. Nested relations are supported too, with no need to specify the model.

from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [
        AutocompleteFilterFactory('Artist', 'artist', 'admin:custom_search', True)
    ]

    def get_urls(self):
        """As above..."""

More Examples

Nested relations and reverse lookups are supported out of the box.

  1. Filter a log model by users related through a device

Models:

from django.db import models

class Member(models.Model):
    name = models.CharField(max_length=100)

class Device(models.Model):
    slug = models.CharField(max_length=100)
    members = models.ManyToManyField(Member, related_name='devices', blank=True)

class PingLog(models.Model):
    device = models.ForeignKey(Device, related_name='pings', on_delete=models.CASCADE)
    ip = models.CharField(max_length=64, blank=True, default='')

Admin:

from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory
from tests.testapp.models import Member, PingLog

@admin.register(PingLog)
class PingLogAdmin(admin.ModelAdmin):
    list_filter = [
        # Drill-down M2M: filter PingLog by Device.members
        AutocompleteFilterFactory('Member', 'device__members'),
    ]

@admin.register(Member)
class MemberAdmin(admin.ModelAdmin):
    search_fields = ['name']  # required for admin autocomplete
  1. Filter coupons by redeemers and by bug reports that rewarded them

Models:

from django.db import models

class Coupon(models.Model):
    code = models.CharField('Code', max_length=64, unique=True, blank=True, db_index=True)

class CouponUser(models.Model):
    coupon = models.ForeignKey(Coupon, related_name='users', on_delete=models.DO_NOTHING)
    user = models.ForeignKey('auth.User', related_name='coupons', null=True, on_delete=models.SET_NULL)
    redeemed_at = models.DateTimeField('Used', auto_now_add=True)

class BugReport(models.Model):
    title = models.CharField(max_length=1024)
    reward_coupon = models.ForeignKey(Coupon, on_delete=models.DO_NOTHING, null=True, blank=True)

Admin:

from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory
from tests.testapp.models import BugReport, Coupon

@admin.register(BugReport)
class BugReportAdmin(admin.ModelAdmin):
    search_fields = ['title']

@admin.register(Coupon)
class CouponAdmin(admin.ModelAdmin):
    list_filter = [
        # Through model to auth.User
        AutocompleteFilterFactory('User', 'users__user'),
        # Reverse FK using default related_query_name 'bugreport'
        AutocompleteFilterFactory('Bug Report', 'bugreport'),
    ]

Notes:

  • For each remote model you filter by (e.g., Member, BugReport), its ModelAdmin must define search_fields so the admin autocomplete endpoint works (Django 4.2+ requirement).
  • By default, AutocompleteFilterFactory points to the package’s auto-registered admin view, available at admin:admin-autocomplete. (otherwise it fails due to get_limit_choices_to being required on non-fk Fields). You can override this by specifying a custom view, as shown above.

Customizing widget text

You can customize the text displayed in the filter widget, to use something other than str(obj). This needs to be configured for both the dropdown endpoint and the widget itself.

In your views.py, override display_text:

from admin_auto_filters.views import AutocompleteJsonView


class CustomSearchView(AutocompleteJsonView):

    @staticmethod
    def display_text(obj):
        return obj.my_str_method()

    def get_queryset(self):
        """As above..."""
        ...

Then use either of two options to customize the text.

Option one is to specify the form_field in an AutocompleteFilter in your admin.py:

from django import forms
from django.contrib import admin
from django.shortcuts import reverse
from admin_auto_filters.filters import AutocompleteFilter


class FoodChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.my_str_method()


class ArtistFilter(AutocompleteFilter):
    title = 'Artist'
    field_name = 'artist'
    form_field = FoodChoiceField

    def get_autocomplete_url(self, request, model_admin):
        return reverse('admin:custom_search')


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [ArtistFilter]

    def get_urls(self):
        """As above..."""

Option two is to use an AutocompleteFilterFactory in your admin.py add a label_by argument:

from django.contrib import admin
from admin_auto_filters.filters import AutocompleteFilterFactory


class AlbumAdmin(admin.ModelAdmin):
    list_filter = [
        AutocompleteFilterFactory('Artist', 'artist', 'admin:custom_search', True, label_by='my_str_method')
    ]

    def get_urls(self):
        """As above..."""

Contributing:

This project is a combined effort of a lot of selfless developers who try to make things easier. Your contribution is most welcome.

Please make a pull-request to the branch master, make sure your branch does not have any conflicts, and clearly mention the problems or improvements your PR is addressing.

Verify that tests and linting pass in the Pull Request checks.

License:

Django Admin Autocomplete Filter is an Open Source project licensed under the terms of the GNU GENERAL PUBLIC LICENSE.

Metadata

Release files for django-admin-autocomplete-filters 0.8.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-admin-autocomplete-filters 0.8.1
File Size Uploaded
django_admin_autocomplete_filters-0.8.1.tar.gz 28.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-admin-autocomplete-filters 0.8.1
File Interpreter ABI Platform
django_admin_autocomplete_filters-0.8.1-py3-none-any.whl Python 3 none any Details

Total release size: 53.6 kB

Release files / django_admin_autocomplete_filters-0.8.1.tar.gz

Download URL django_admin_autocomplete_filters-0.8.1.tar.gz
Size 28.3 kB
Tags Source
SHA-256 checksum
How to use checksums
118d879f79812ea65b8d59f5fe9bc78c771288897e1e47690e100329e698781d
BLAKE2b-256 checksum
How to use checksums
a53484a8bbc2840054e95293c682a66977a61a2d0df6f0dde512e29420c6916a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / django_admin_autocomplete_filters-0.8.1-py3-none-any.whl

Download URL django_admin_autocomplete_filters-0.8.1-py3-none-any.whl
Size 25.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d87b8b57f8e1b7d8722137ea79c34ed1b3663436d34fcdd5b5b42187f2c34bf0
BLAKE2b-256 checksum
How to use checksums
66a64fcb86e1b641bb5eb9f55f1165a6ed23d5d65ee9a2b96d163315b7c1c471
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.1 This release

2 release files

0.8.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page