## Django’s ArrayField is a nifty Field API feature that avoids unnecessary tables when advanced aggregations aren’t needed. Yet, there’s no native helper for a simple admin list filter based on an ArrayField. Let’s fill the gap!
Say you have a WebPage model with a domains ArrayField. You could use a clean solution and have a list filter for that field, requiring only a display title and the query string parameter name:
class DomainsListFilter(ArrayFieldListFilter):
"""An admin list filter for domains."""
title = "domain"
parameter_name = "domains"
To achieve this, we can have the ArrayFieldListFilter class helper inherit from [SimpleListFilter](https://docs.djangoproject.com/en/3.2/ref/contrib/admin/). In the lookups method override, we can parse the input received from the domains field as a lexicographically sorted list of non-falsy values for the filter widget and also replace the original queryset method to have the URL lookup value processed in two alternative control branches -- allowing for either a proper (non-exact) value or an empty one disabling the filtering altogether.
from django.contrib.admin import SimpleListFilter
class ArrayFieldListFilter(SimpleListFilter):
"""An admin list filter for ArrayFields."""
def lookups(self, request, model_admin):
"""Return the filtered queryset."""
queryset_values = model_admin.model.objects.values_list(
self.parameter_name, flat=True
)
values = []
for sublist in queryset_values:
if sublist:
for value in sublist:
if value:
values.append((value, value))
else:
values.append(("null", "-"))
return sorted(set(values))
def queryset(self, request, queryset):
"""Return the filtered queryset."""
lookup_value = self.value()
if lookup_value:
lookup_filter = (
{"{}__isnull".format(self.parameter_name): True}
if lookup_value == "null"
else {"{}__contains".format(self.parameter_name):
[lookup_value]}
)
queryset = queryset.filter(**lookup_filter)
return queryset
Finally, all is left to do is to use the class in the ModelAdmin, like so:
from django.contrib import admin
class WebPageAdmin(admin.ModelAdmin):
"""The web page admin."""
list_filter = (DomainsListFilter,)
The code used to be a Github gist and is currently being evaluated for integration in the django-more-admin-filters package.