Autocomplete does nothing. What is wrong?

Viewed 415

I have autocomplete code which does not work.

I have input field class Coordinate where when i type code it finds value from my DB that matches with geo_code and hence finds the input code country.

So when i type UK it matches with geo_code and then matches the last with the country so in this case UK is code i type it can be found in geo_code and country is United Kingdom. The code works, what i want to achieve is bring autocomplete to give suggestions while typing. for examples:

UK   United Kingdom
USA  United States of America

What i did so far:

In models.py i have:

class Coordinate(models.Model):
    code = models.CharField(max_length=150)

class Profiles(models.Model):
    geocode=models.CharField(max_length=200)
    country=models.CharField(max_length=500)
    city=models.CharField(max_length=500)

    class Meta:
        managed=False
        db_table='profiles_country'

    def __str__(self):
        return '{}'.format(self.geocode)

in forms.py:

from dal import autocomplete

class CoordinateForm(forms.ModelForm):
    code= forms.CharField(max_length=150, label='',widget= forms.TextInput)

    class Meta:
        model = Coordinate
        fields = ('__all__')
        widgets = {
            'code': autocomplete.ModelSelect2(url='coordinate-autocomplete')}

in views.py:

class CoordinateAutocomplete(autocomplete.Select2QuerySetView):
        def get_queryset(self):
            if not self.request.user.is_authenticated():
                return Profiles.objects.none()
            qs = Profiles.objects.all()
            if self.q:
                qs = qs.filter(name__istartswith=self.q)
            return qs

in base.html

<!DOCTYPE html>
{% load static %}

<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">

    <link rel="stylesheet" href="{% static 'geoproj/css/main.css' %}">

  </head>
  <body>

    <div>{% block content %}{% endblock  %} 

         {% block javascripts %} {% endblock %} </div>

  </body>
</html>

in geo.html :

{% extends "base.html" %}
{% block content %}

{% if user.is_authenticated %}
            <form enctype="multipart/form-data" method="POST" >
                    {% csrf_token %}
                    {{ form}}
                    {{form.media }}
            <button class = "btn btn-primary" type="submit">OK</button></form>


{% endif %}

{% endblock content %}

{% block javascripts %} {% endblock %}

I would appreciate you help to solve this case.

3 Answers

I don't see the js that links the URL response and HTML template. Here how I will solve it. Provided your view works. You will generate the suggestion by

  1. First Creating a js event listener to get text from the input box of the form
  2. Once you get this text you will do an ajax call to the view URL you have mention
  3. After you get ajax result you will then create a for loop and generate select tags for the input.

This is how I would write the js code to communicate with the Html template and Django autocomplete view URL.

code field in the CoordinateForm is CharField, not ModelChoiceField, so it fails to work correctly with QuerySet returned by autocomplete.

models.py:

class Coordinate(models.Model):
    code = models.CharField(max_length=150)
    def __str__(self):
        return self.code

class Profiles(models.Model):
    geocode=models.CharField(max_length=200)
    country=models.CharField(max_length=500)
    city=models.CharField(max_length=500)

    class Meta:
        managed=False
        db_table='profiles_country'

    def __str__(self):
        return '{}'.format(self.geocode)

views.py:

def geoview(request):
    if request.method == "POST":
        #do your operations
        return render(request, 'result.html')

    return render(request, 'index.html')


def getgeocode(request, geocode):
    results = Coordinate.objects.filter(code__istartswith=str(geocode))
    sendres = ""
    for resn in results[:10]:
        sendres += "<option class='bg-primary'>" + resn.code + "</option>"
    return HttpResponse(sendres)

index.html:

{% extends 'base.html' %}

{% block content %}
    <form enctype="multipart/form-data" method="POST">
        <input type="text" list="mylist" name="geocodes" id="geocodes" placeholder="enter geocde"
               onkeyup="getGeoCode(this.value)" autocomplete="off"/>
        <datalist id="mylist">
        </datalist>

        <button class="btn btn-primary" type="submit">OK</button>
    </form>
{% endblock content %}
{% block javascripts %}
    <script>
        function getGeoCode(str) {
            if (str.length == 0) {
                document.getElementById("mylist").innerHTML = "";
                document.getElementById("mylist").style.border = "0px";
                return;
            }
            if (window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
            } else {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.onreadystatechange = function () {
                if (this.readyState == 4 && this.status == 200) {
                    document.getElementById("mylist").innerHTML = this.responseText;
                }
            }
            xmlhttp.open("GET", "/coordinate-autocomplete/" + str, true);
            xmlhttp.send();
        }
    </script>
{% endblock javascripts %}

urls.py:

from django.urls import path
from app import views

urlpatterns = [
    ....
    path('geo/', views.geoview, name='geo'),
    path('coordinate-autocomplete/<geocode>', views.getgeocode, name='coordinate-autocomplete'),
    ....
]

enter image description here

enter image description here

and you can confirm its working in your terminal you will see get request like: /coordinate-autocomplete/{word_in_iput}

[17/Apr/2020 16:19:52] "GET /coordinate-autocomplete/u HTTP/1.1" 200 120
[17/Apr/2020 16:20:03] "GET /coordinate-autocomplete/us HTTP/1.1" 200 65
[17/Apr/2020 16:20:06] "GET /coordinate-autocomplete/u HTTP/1.1" 200 120
[17/Apr/2020 16:20:13] "GET /coordinate-autocomplete/i HTTP/1.1" 200 44
Related