How to change the Django admin filter to use a dropdown instead of list?

DjangoDjango Admin

Django Problem Overview


If, for a field that you want to filter by, you have more than ~10 values, the filtering sidebar starts to be ugly and harder to use.

I'm looking for a solution to replace the <li> with a dropdown selection (combobox) or something similar that will solve the same problem.

Django Solutions


Solution 1 - Django

Thanks @beholderrk, @gediminas and @jk-laiho! I packaged this into a reusable app.

Install:

pip install django-admin-list-filter-dropdown

Enable in settings.py:

INSTALLED_APPS = (
    ...
    'django_admin_listfilter_dropdown',
    ...
)

Use in admin.py:

from django_admin_listfilter_dropdown.filters import (
    DropdownFilter, ChoiceDropdownFilter, RelatedDropdownFilter
)

class EntityAdmin(admin.ModelAdmin):
    ...
    list_filter = (
        # for ordinary fields
        ('a_charfield', DropdownFilter),
        # for choice fields
        ('a_choicefield', ChoiceDropdownFilter),
        # for related fields
        ('a_foreignkey_field', RelatedDropdownFilter),
    )

Here's what it looks like:

Screenshot of dropdown list filter

Solution 2 - Django

I cannot comment answers so I'll add to beholderrk's answer here.

  1. create a new template called dropdown_filter.html or similar

  2. copy the code of filter.html from feincms to dropdown_filter.html

  3. create a new filter class in filters.py:

    from django.contrib.admin.filters import AllValuesFieldListFilter
    
    class DropdownFilter(AllValuesFieldListFilter):
        template = 'admin/dropdown_filter.html'
    
  4. now you can use this filter in your admin class:

    class SomeAdmin(admin.ModelAdmin):
        # ...
        list_filter = (('country', DropdownFilter),)
    

Works great!

Solution 3 - Django

Use filter.html from feincms

{% load i18n %}
<script type="text/javascript">var go_from_select = function(opt) { window.location = window.location.pathname + opt };</script>
<h3>{{ title }}</h3>
<ul class="admin-filter-{{ title|cut:' ' }}">
{% if choices|slice:"4:" %}
    <li>
    <select style="width: 95%;"
        onchange="go_from_select(this.options[this.selectedIndex].value)">
    {% for choice in choices %}
        <option{% if choice.selected %} selected="selected"{% endif %}
         value="{{ choice.query_string|iriencode }}">{{ choice.display }}</option>
    {% endfor %}
    </select>
    </li>
{% else %}

    {% for choice in choices %}
            <li{% if choice.selected %} class="selected"{% endif %}>
            <a href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li>
    {% endfor %}

{% endif %}
</ul>

Solution 4 - Django

An easy option would be to use django-grappelli, which replaces all the filters with drop downs.

Solution 5 - Django

You can copy the admin templates from the django installation into you templates/admin folder in your project.

Then you will need to do any of 2 things in the forms or templates you want to show your outputs in:

  1. If you are working with a form, in that you would like the list choices to be posted back to a database, you would in your model.py, on the field you have your choices, put in some this like this:

    choice = forms.IntegerField(widget=forms.Select(choices=CHOICES))

  2. If it is just to display on a page, then you will output on a template tag something like this:

Solution 6 - Django

http://djangosuit.com/ also offers dropdowns for list filters.

Solution 7 - Django

I am not a fan of all solutions provided up to now.

Why? If, for a field that you want to filter by, you have more than 10 values, a listview box isn't that handy, too. I advice to use the standard search field capability of django admin which will show you a search field:

class BooksAdmin(admin.ModelAdmin):
    list_display = ('ISBN', 'title')         
    search_fields = ('ISBN',)
    # instead of: list_filter = ('ISBN',)
    ordering = ('title',)  

Solution 8 - Django

The best solution is to create a new template in admin/filter.html and implement the HTML code suggested by @beholderrk. Just implemented it for a client and it works great.

Problem with DropdownFilter and RelatedDropdownFilter is that it loses the proper display. Instead of the translated strings for Charfield(choices=xxx), it will show True, False and so on.

Solution 9 - Django

Could you please give a complete example. it shows like before. here is my code

from django.contrib import admin
from pages.models import Post, Device, DeviceType, DeviceModel, Ipaddress, DeviceGroup, Location,Department,Comment
from django_admin_listfilter_dropdown.filters import DropdownFilter, RelatedDropdownFilter


class CommentInline(admin.TabularInline):
    model = Comment

class IpaddressAdmin(admin.ModelAdmin):
        prepopulated_fields = {'slug': ('ipaddress',)}
#        model=Ipaddress
     
        search_fields = ['ipaddress', ]
#     
        list_display = ('ipaddress', 'machinename', 'user', 'department','location',)
        list_filter = (
        ('user', DropdownFilter),
        ('department', RelatedDropdownFilter),
        ('location', RelatedDropdownFilter),
        
    )

Here is the screenshotenter image description here

Solution 10 - Django

I was struggling with the same problem some few weeks back. So this answer might be useful to some developers from the future.

I managed to solve the problem by writing a custom template.html

I have bundled the code in an amazing package now that does the same for you, here's the link.


Here's how you can implement a Searchable Dropdown in place of the default List:

1. Installation:

pip install django-admin-searchable-dropdown

This command will install the latest version of the package in your project.
Now, include the package in your project by adding admin_searchable_dropdown to your INSTALLED_APPS inside settings.py file.

2. Usage:
Let's say you have following models:

from django.db import models

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

class CarModel(models.Model):
    name = models.CharField(max_length=64)
    company = models.ForeignKey(CarCompany, on_delete=models.CASCADE)

And you would like to filter results in CarModelAdmin on the basis of company. You need to define search_fields in CarCompany and then define filter like this:

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


class CarCompanyFilter(AutocompleteFilter):
    title = 'Company' # display title
    field_name = 'company' # name of the foreign key field


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


class CarModelAdmin(admin.ModelAdmin):
    list_filter = [CarCompanyFilter]
    # ...

After following these steps you may see the filter as:

  1. This is how the list filter is rendered in the form of a dropdown when the package is used
  2. And the dropdown filter is also Searchable

Features Offered:

  1. If you have large fields in Admin Filter, the sidebar gets widened, this package provides you the same list in a dropdown format, hence, no such hassle.
  2. If you have more than, say 20, field items, list filter is now a long side-pane, just ruining the admin interface. The Dropdown filter fixes that.
  3. The Dropdown is also "Searchable", with an input text field (which utilizes Django's own auto_complete functionailty), so as long as the Django version you are using is greater than 2.0, you should be fine.
  4. You can customize other list_filters you may have, like change the Title above the dropdown, or a custom Search logic etc.
  5. You can customize Widget Texts to display in the Dropdown Option to use something other than the default str(obj)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsorinView Question on Stackoverflow
Solution 1 - DjangomrtsView Answer on Stackoverflow
Solution 2 - DjangoGediminasView Answer on Stackoverflow
Solution 3 - DjangobeholderrkView Answer on Stackoverflow
Solution 4 - DjangoBernhard VallantView Answer on Stackoverflow
Solution 5 - DjangoAfrowaveView Answer on Stackoverflow
Solution 6 - Djangouser3061675View Answer on Stackoverflow
Solution 7 - DjangoVengaVengaView Answer on Stackoverflow
Solution 8 - DjangoÖzerView Answer on Stackoverflow
Solution 9 - DjangoRanaView Answer on Stackoverflow
Solution 10 - DjangoAshish YadavView Answer on Stackoverflow