Search code examples
djangodjango-modelsdjango-formsdjango-admindjango-autocomplete-light

Searchable drop down for choice field in django admin


I have a choice field with lot's of data, I have created drop down at admin panel but I want to have a searchable drop down.

class ItemForm(forms.ModelForm):

   def __init__(self, *args, **kwargs):
       super(PublicUserForm, self).__init__(*args, **kwargs)
       self.fields['city'] = forms.ChoiceField(
       choices = CHOOSE_CITY) 

class ItemAdmin(admin.ModelAdmin):
   form = ItemForm

admin.site.register(Item, ItemAdmin)

I have reffered django-autocomplete-light.

Thanks in advance!


Solution

  • Follow these steps

    Install django autocomplete light using pip

    pip install django-autocomplete-light
    

    Then, to let Django find the static files we need by adding to INSTALLED_APPS, before django.contrib.admin and grappelli if present

    'dal',
    'dal_select2',
    #'grappelli',
    'django.contrib.admin',
    

    Now You need to create an autocomplete view that will respond with filtered queryset when you search.

    from dal import autocomplete
    
    from your_app.models import City
    
    
    class CityAutocomplete(autocomplete.Select2QuerySetView):
        def get_queryset(self):
    
            if not self.request.user.is_authenticated:
                return City.objects.none()
    
            qs = City.objects.all()
    
            if self.q:
                qs = qs.filter(name__istartswith=self.q)
    
            return qs
    

    Note: The base view for autocomplete view should be Select2QuerySetView.

    Now register the autocomplete view Create a named url for the view

    from your_app.views import CityAutocomplete
    
    urlpatterns = [
        url(
            r'^city-autocomplete/$',
            CityAutocomplete.as_view(),
            name='city-autocomplete',
        ),
    ]
    

    You can now use the autocomplete view in Item form. use ModelSelect2 to create widget

    from dal import autocomplete
    
    from django import forms
    
    
    class ItemForm(forms.ModelForm):
        city = forms.ModelChoiceField(
            queryset=City.objects.all(),
            widget=autocomplete.ModelSelect2(url='city-autocomplete')
        )
    
        class Meta:
            model = Item
            fields = ('__all__')
    

    Now you can easily use it in admin.

    from your_app.forms import ItemForm
    
    class ItemAdmin(admin.ModelAdmin):
       form = ItemForm
    
    admin.site.register(Item, ItemAdmin)
    

    Note: This will work if you have city field as a foreign key in the Item model.


    If city is a Choice field you can use autocompleting based on a list of Strings

    Create a listview using Select2ListView and override get_list method

    class CityAutocomplete(autocomplete.Select2ListView):
        def get_list(self):
            # return all cities name here, it will be auto filtered by super class
            return ['Pune', 'Patna', 'Mumbai', 'Delhi', ...]
    

    Register URL as above, now modify your model form and use Select2ListChoiceField

    def get_choice_list():
        # all cites to used as chice list
        return ['Pune', 'Patna', 'Mumbai', 'Delhi', ...]
    
    
    class ItemForm(forms.ModelForm):
        city = autocomplete.Select2ListChoiceField(
            choice_list=get_choice_list,
            widget=autocomplete.ListSelect2(url='city-autocomplete')
        )
    
        class Meta:
            model = Item
            fields = ('__all__')
    

    Add this form to ModelAdmin as we did in above example.