harwalan
harwalan

Reputation: 847

Django, jQuery, and autocomplete

After some extensive research (Googling), I cannot find a current tutorial on how to set up autocomplete using Django and jQuery. There appears to be a variety of plugins and there appears to be no consistency or standard about which to use or when.

I'm not a pro at either Django or jQuery, but need an autocomplete solution that is well documented and fairly simple to utilize.

Suggestions?

Upvotes: 26

Views: 35445

Answers (10)

revliscano
revliscano

Reputation: 2272

Let's say you want to set up autocomplete on some input field (like <input type="text" id="id_input">) with the username of your users. This is the way I did it:

urls.py

First of all, add a url that will be used by the AJAX call.

url(r'^ajax/autocomplete/$', views.autocomplete, name='ajax_autocomplete')

views.py

Then set a view to retrieve the information (i.e the usernames, in this case) from the database

from django.http import JsonResponse

def autocomplete(request):
    if request.is_ajax():
        username_query = request.GET.get('username_query', '')
        usernames = (User.objects
                     .filter(username__startswith=username_query)
                     .values_list('username', flat=True))
        data = {
            'usernames': usernames,
        }
        return JsonResponse(data)

JavaScript

Finally, you need to make a JavaScript function that goes to the database and returns the usernames that match with the value of the input field every time you press (and release) a key. For this, we are going to use Ajax, JQuery and the JQuery-ui's autocomplete function

jQuery(function() {
    $("#id_input").on('keyup', function(){
        let value = $(this).val();
        $.ajax({
            url: "{% url 'ajax_autocomplete' %}",
            data: {
              'username_query': value 
            },
            dataType: 'json',
            success: function (data) {
                let usernames = data.usernames;
                $("#id_input").autocomplete({
                source: usernames,
                minLength: 3 
                });       
            }
        });        
    });
  });

And that's it! For more information, you can check out this tutorial

Upvotes: 6

rkp768
rkp768

Reputation: 56

I find https://www.w3schools.com/howto/howto_js_autocomplete.asp tutorial to be good. The tutorial uses a static countries array from which the autocomplete function selects the responses(dropdown elements).

Now to make the same more dynamic we can add simple jQuery ajax call to a Django view.

var countries;
$.ajax({
    url : '/autocomplete_view';
    data : {'query':$('#query').val()};
    type : 'GET',
    success : function(response){
        countries = JSON.parse(response);
        // do something extra
    },
    failure : function(response){
        // do something here
    },
    async : false
});

Upvotes: 1

Alouani Younes
Alouani Younes

Reputation: 1036

I know that implementing jQuery autocomplete is tricky. Here is a working example for Django > 2.0:

Step 1: Create a simple HTML with an input (Don't forget to add links to load jQuery and jquery-ui). Save the code as testsearch.html

<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script> 
</head>
<div class="ui-widget">
  <label for="search"> Search </label>
  <input id="search">
</div>

Step 2: Add a JavaScript code to the html. It calls the function autocomplete from jquery-ui. This function uses a source which the URL for Ajax calls

<script type="text/javascript">
$(function() {
  $("#search").autocomplete({
    source: "{% url 'project:ajax_load_project' %}",
    minLength: 2,
  });
});
</script>

Step 3: Now we need to create two functions. A simple function to render testsearch.html and another one that receives Ajax calls and send back data.

def ajax_load_project(request):
    if request.is_ajax():
        q = request.GET.get('term', '')
        print(q)
        projects = Project.objects.filter(title__istartswith=q)[:5]
        results = []
        for project in projects:
            project_json = {}
            project_json['id'] = project.id
            project_json['value'] = project.title
            project_json['label'] = project.title
            results.append(project_json)
        data = json.dumps(results)
    else:
        data = 'fail'
    mimetype = 'application/json'
    return HttpResponse(data, mimetype)

def searchProject(request):
    template = 'project/testsearch.html'
    return render(request, template)

Project is my model. You can replace it with your Model. Replace title with the field used for searching.

For my example you can create this simple Model:

class Project(models.Model):
    """
    A Model representing a the project.
    """
    title = models.CharField(max_length=200)

Step 4: Don't forget to include two URLs. One for the HTML and the one for Ajax calls

urlpatterns += [
    #test search
    path('SuggestProject/', views.ajax_load_project, name='ajax_load_project'),
    path('searchtest/', views.searchProject, name='searchProject'),]

Upvotes: 3

Ivan Pirus
Ivan Pirus

Reputation: 1076

In django 1.10 I use same code

url:

# Ajax
    url(r'^search-autocomplete/$', autocompleteModel,  name='search-autocomplete'),

view:

def autocompleteModel(request):
    search_qs = Account.objects.filter(email__startswith=request.GET['search'])
    results = []
    for r in search_qs:
        results.append(r.email)
    resp = request.GET['callback'] + '(' + simplejson.dumps(results) + ');'
    return HttpResponse(resp, content_type='application/json')

js:

$(document).ready(function () {
    function searchOpen() {
        var search = $('#countryId').val();
        $.ajax({
            url: '/cabinet/search-autocomplete',
            dataType: 'jsonp',
            type: 'GET',
            async: false,
            data: injectCsrfToken({
                search: search
            }),
            success: function (data) {
                searchResult(data)
            },
            error: function () {
                console.log('error');
            }

        });
    }
    function searchResult(data) {
        console.log('sdfsdfd');
        $( "#countryId" ).autocomplete ({
            source: data
        });
    }
    $("#countryId").on('keyup', function () {
        searchOpen();
    });
});

html:

<input id="countryId" type="text" name="fname">

Upvotes: 0

J0ANMM
J0ANMM

Reputation: 8535

I found that the simplest way to get started (although probably not the optimal for production) is with JQuery Autocomplete Widget.

The most basic way just requires to copy-paste the code into your html, using an array as a source:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Autocomplete - Cities example</title>
  <link href="style.css" rel="stylesheet">

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>

<body>  
<div class="ui-widget">
  <label for="tags">Cities: </label>
  <input id="tags">
</div>

<script>
    $( function() {
      var availableTags = [
          'Barcelona',
          'Berlin',
          'London',
          'Madrid',
          'Rome',
          'Paris'
      ];
      $( "#tags" ).autocomplete({
        source: availableTags
      });
    } );
</script>

</body>
</html>

Upvotes: 0

Rishabh Agrahari
Rishabh Agrahari

Reputation: 3717

There's a way without using Json:

example: let's assume you have a model named College:

class College(models.Model):
    collegeName = models.CharField(max_length=250)
    def __str__(self):
        return self.collegeName

Now, render a context named 'all_colleges' = College.objects.all() to your template,:

HTML:

<input type="text" id="college"/>

JS:

  $( function() {
    var availableColleges = [
      {% for clg in all_colleges %}
          "{{clg}}",
      {%endfor%}
    ];
    $( "#clg" ).autocomplete({
      source: availableColleges
    });
  } );

Resources to be included in the template:

<link rel="stylesheet" href="http://code.jquery.com/ui/1.8.18/themes/base/jquery-ui.css" type="text/css" media="all" />
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>

That's it!

If you need autocomplete to show options which start with the term entered, modify the default filter autocomplete filter function by adding this snippet in your template:

 // over write the default autocomplete function to match the option starting with entered term 
  $.ui.autocomplete.filter = function (array, term) {
    var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
    return $.grep(array, function (value) {
      return matcher.test(value.label || value.value || value);
    });
  };

Comment if you face any problem :)

Upvotes: 0

chiseledCoder
chiseledCoder

Reputation: 385

django-autocomplete-light is very nice option. It is very easy to use and also documented very well. Link: https://github.com/yourlabs/django-autocomplete-light

Documentation: https://django-autocomplete-light.readthedocs.org/en/master/

Upvotes: 1

Mihai Zamfir
Mihai Zamfir

Reputation: 2166

Meanwhile, a good tutorial appeared.

autocomplete does everything for you, all you have to do is the following:

js

$(function() {
  $("#search-field").autocomplete({
    source: "/ajax_calls/myFunction",
    minLength: 2,
  });
});

urls.py

url(r'^ajax_calls/myFunction/', 'my_app.views.handler_function'),

views.py

def get_drugs(request):

    if request.is_ajax():
        .....
        data = json.dumps(results)
    else:
        data = 'fail'
    mimetype = 'application/json'
    return HttpResponse(data, mimetype)

SOURCE: http://flaviusim.com/blog/AJAX-Autocomplete-Search-with-Django-and-jQuery/

Upvotes: 7

CraigKerstiens
CraigKerstiens

Reputation: 5954

If you're looking to search from within your django models then something like:

from django.utils import simplejson
    def autocompleteModel(request):
    search_qs = ModelName.objects.filter(name__startswith=request.REQUEST['search'])
    results = []
    for r in search_qs:
        results.append(r.name)
    resp = request.REQUEST['callback'] + '(' + simplejson.dumps(result) + ');'
    return HttpResponse(resp, content_type='application/json')

For the jQuery autocomplete and call:

function searchOpen() {
    var search = $('#txtSearch').val()
    var data = {
        search: search
    };
    $.ajax({
        url: '/search.json',
        data: data,
        dataType: 'jsonp',
        jsonp: 'callback',
        jsonpCallback: 'searchResult'
    });
}


function searchResult(data) {
    $( "#txtSearch" ).autocomplete ({
        source: data
    });
}

Finally to connect it all on your input form would have something like:

<input type="text" name="search" id="txtSearch" onkeyup="searchOpen()" />

Note, this is using Jquery UI as well in addition to stock jQuery.

Upvotes: 19

JudoWill
JudoWill

Reputation: 4811

I'm a big fan of django-autocomplete: https://bitbucket.org/tyrion/django-autocomplete/wiki/Home . Its got a nice plug-and-play and is very easy to integrate with your own apps without much additional coding.

Upvotes: 4

Related Questions