[Fixed]-How to create a autocomplete input field in a form using Django

27πŸ‘

βœ…

I finally got the autocomplete search working using the instructions found here

https://github.com/xcash/bootstrap-autocomplete
https://bootstrap-autocomplete.readthedocs.io/en/latest/

It is very simple to use and does not need to install any app in settings.py and it works for both bootstrap 3 and bootstrap 4

There are lot of other packages available but this was simple and easy for my need.

I am going to explain the code I used

page.html

{% block script %}
    <script src="https://cdn.rawgit.com/xcash/bootstrap-autocomplete/3de7ad37/dist/latest/bootstrap-autocomplete.js"></script>
    <script>
        $('.basicAutoComplete').autoComplete(
            {minLength: 1}
        );
        $('.dropdown-menu').css({'top': 'auto', 'left': 'auto'})

    </script>
{% endblock %}
.
.
.
.
.
{% if field.name == "from_email" %}
   {% render_field field class="basicAutoComplete form-control" %}
{% else %}
   {% render_field field class="form-control" %}
{% endif %}

autoComplete is the function called to perform the action and minLength specifies the minimum length of the text before performing the fetch action
I added an extra CSS to fix the autocomplete dropdown otherwise it was weird.

The Jinja render kept overwriting the class definition from views so I added an if check for it.

urls.py

from . import views

urlpatterns = [
    .
    .
    .
    path('email_autocomplete/', views.email_autocomplete, name='email_autocomplete')
]

Added this line to urls.py

forms.py

class LeaveForm(forms.Form):
    from_email = forms.EmailField(required=True, widget=forms.TextInput(
        attrs={
            'style': 'width: 400px',
            'class': 'basicAutoComplete',
            'data-url': "/domain/email_autocomplete/"
        }))

The above is the code for the input field in forms.py. data-url points to where the JSON result would be generated.

views.py

from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from .models import model
        
def email_autocomplete(request):
    if request.GET.get('q'):
        q = request.GET['q']
        data = model.objects.using('legacy').filter(email__startswith=q).values_list('email',flat=True)
        json = list(data)
        return JsonResponse(json, safe=False)
    else:
        HttpResponse("No cookies")
            

This was the most confusing part for me. The GET request is easy to understand but it took a while to convert the data from model.objects into a JSON formatted object. The trick was to use

values_list('columnName',flat=True)

when filtering the data from the database, then converting to a list using list(data) and finally use JsonResponse to convert it to JSON.

Hope this will help any one who wants a simple autocomplete

2πŸ‘

You can consider a different way to get the autocompletion for the input element using the standard HTML tag <datalist>.

Consider the example below. It does not use Javascript and it does not need anything to do in the server code.

<input list="browsers" id="browser_id" name="browser" placeholder="Starting typing the name of the browser" size="50"/>
<datalist id="browsers">
  <option>Chrome</option>
  <option>Firefox</option>
  <option>Internet Explorer</option>
  <option>Opera</option>
  <option>Safari</option>
  <option>Microsoft Edge</option>
</datalist>

The documentation about the tag is here – https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist

πŸ‘€Alexander

1πŸ‘

A very little addition.
The answer of Abilash is great and very clear.
But if it doesn’t work for you, may be you should wrapping you basicAutoComplete activation into

$(document).ready(function(){
};

The reason and some explanation could be found here :
Bootstrap Auto-complete Error: Cannot read property " " of undefined

πŸ‘€Paul Zakharov

Leave a comment