Search code examples
pythonajaxdjangodynamic-list

How can Ajax work with a dynamic Django dropdown list?


I'm making this little web app that takes 2 addresses, calculates the distance using google maps, and calculates the gas cost based on the vehicles mpg rating. Everything is complete except for this last part that I believe would work best with AJAX.

I have 3 lists (year, make, model), and I need the list of car models to be restricted based on the year and make of the car. After selecting, I have a button that once clicked, will verify if it is a valid vehicle in the database and pull the vehicle's mpg rating to do some basic math on it.

The problem is I don't really know how to approach this problem. I've searched some inquiries the past few hours and I'm getting a lot of things related to model forms and Django choice fields which I don't want to get into if I don't have to. My idea is to just change the innerText/value, and check it against my django database.

I also came across this answer from SO:

How do I integrate Ajax with Django applications?

and am a bit confused by it. If I understand correctly, the AJAX GET request will extract data in javascript objects the same as if I visited that url as a user. Does this mean I could just create another html template and post every vehicle in the database onto that page from which I can extract info and create my dynamic lists from?

Looking for the most straightforward way to dynamically generate my lists with ajax and verify the year, make, and model with my database which will then return the car's mpg.

models.py:

class Car(models.Model):
    year = models.IntegerField(default=0)
    make = models.CharField(max_length=60)
    model = models.CharField(max_length=60)
    mpg = models.IntegerField(default=0)


    def __str__(self):
        return ("{0} {1} {2}".format(self.year, self.make, self.model))

views.py: (right now, it just lists every vehicle and has no way to verify the vehicle on the spot)

def index(request):

    context_dic = {}
    car_list = Car.objects.order_by('make')
    car_list_model = Car.objects.order_by('model')
    context_dic['car_list'] = car_list
    context_dic['years'] = []
    context_dic['makes'] = []
    context_dic['models'] = []

    for year in range(1995, 2016):
        context_dic['years'].append(year)

    for make in car_list:
        if make.make not in context_dic['makes']:
            context_dic['makes'].append(make.make)
        else:
            continue

    for model in car_list_model:
        if model.model not in context_dic['models']:
            context_dic['models'].append(model.model)
        else:
            continue

    return render(request, 'ConverterApp/index.html', context_dic)

html: (x3 for the make and model)

<div id="specifics">
    <div class="dropdown" id="year-dropdown">
      <button class="btn btn-default dropdown-toggle" type="button"
      id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
        Year
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
    {% for year in years %}
      <li><a href="#">{{ year }}</a></li>
    {% endfor %}
  </ul>
</div>

javascript: (just shows the value right now, but can't verify with the database)

  $('#calculate').on('click', function ()
  {
    $(this).siblings()[0].textContent = (
      document.getElementById("dropdownMenu1").textContent
      + " " + document.getElementById("dropdownMenu2").textContent
       + " " + document.getElementById("dropdownMenu3").textContent
       + " " + document.getElementById("specifics-gas").value
    )
  });
});

  //this part changes the year, make, model to what the user selects //from the list
  $('li').on('click', function () {
    $(this).parent().siblings()[0].innerHTML = this.innerHTML
    //console.log(this.textContent)
  });

Solution

  • I would go for a REST service, like Django Rest Framework, and then use jquery to autopopulate the dropdowns.

    If installing a REST service is a hassle, you could write a couple of views to get the data in json format...

    For instance, if you have a REST service in /myapp/api, you could populate the Cars like this:

    $.ajax({
        url: "/myapp/api/cars?format=json",
        dataType: "json",
        success: function( data ) {
            var makes=[];  
            for (var i in data) {
                car = data[i];
                if (makes.indexOf(car.make) < 0){ // avoid duplicate brands
                    makes.push(car.make);
                    $('#makeselect').append($('<option>', {
                        value: car.id,
                        text: car.make
                    }));
                }
            }
        }
    });
    

    Then, attach a handler when the "make" selector has changed, and populate the model and year accordingly using another REST call, like /myapp/api/cars?make=Ford