I am building a car repair estimator and need to create a dependent dropdown that will allow users to select from a variety of Models that depend on the Make that they've chosen. I'm able to see and select different Makes, but I am unable to see the different Models. I am using Django framework and have stored the Makes, and Models in a Postgresql database
Here is what is happening with my app right now: Ford models are supposed to be here
Here is a snapshot of my working director of my app, AutoBuddy: Working Directory
Here is the code from my ABDjango/templates/models/home.html file:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Dependent Dropdown in Django</title>
</head>
<body>
<h2>Car Form</h2>
<form method="post" id="modelForm" data-models-url="{% url 'ajax_load_models' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#id_model").change(function () {
const url = $("#modelForm").attr("data-models-url"); // get the url of the `load_cities` view
const modelId = $(this).val(); // get the selected country ID from the HTML input
$.ajax({
// initialize an AJAX request
url: url, // set the url of the request (= /persons/ajax/load-cities/ )
data: {
'model_id': modelId // add the country id to the GET parameters
},
success: function (data) { // `data` is the return of the `load_cities` view function
$("#id_model").html(data); // replace the contents of the city input with the data that came from the server
/*
let html_data = '<option value="">---------</option>';
data.forEach(function (city) {
html_data += `<option value="${city.id}">${city.name}</option>`
});
console.log(html_data);
$("#id_city").html(html_data);
*/
}
});
});
</script>
</body>
</html>
Here is the code from my ABDjango/templates/models/model_dropdown_list_options.html file:
<option value="">---------</option>
{% for model in models %}
<option value="{{ model.pk }}">{{ model.name }}</option>
{% endfor %}
Here is the code from my ABDjango/urls.py file:
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
urlpatterns = [
path('users/', include('autobuddyapp.urls')),
path('admin/', admin.site.urls)
Here is the code from my autobuddy/models.py file:
from django.db import models
class Make (models.Model):
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class Model(models.Model):
make = models.ForeignKey(Make, on_delete=models.CASCADE)
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class Car(models.Model):
year = models.CharField(max_length=124)
make = models.ForeignKey(Make, on_delete=models.SET_NULL, blank=True, null=True)
model = models.ForeignKey(Model, on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.year + " " + str(self.make) + " " + str(self.model)
Here's the code from my autobuddy/urls.py file:
from django.urls import path
from . import views
urlpatterns = [
path('add/', views.model_create_view, name='model_add'),
path('<int:pk>/', views.model_update_view, name='model_change'),
path('ajax/load-models/', views.load_models, name='ajax_load_models'), # AJAX
]
Here's autobuddy/views.py:
from django.http import JsonResponse
from django.shortcuts import render, redirect, get_object_or_404
from .forms import ModelCreationForm
from .models import Make, Model, Car
def model_create_view(request):
form = ModelCreationForm()
if request.method == 'POST':
form = ModelCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('model_add')
return render(request, 'models/home.html', {'form': form})
def model_update_view(request, pk):
car = get_object_or_404(Car, pk=pk)
form = ModelCreationForm(instance=car)
if request.method == 'POST':
form = ModelCreationForm(request.POST, instance=car)
if form.is_valid():
form.save()
return redirect('model_change', pk=pk)
return render(request, 'models/home.html', {'form': form})
# AJAX
def load_models(request):
model_id = request.GET.get('model_id')
models = Model.objects.filter(model_id = model_id).all()
return render(request, 'models/model_dropdown_list_options.html', {'models': models})
# return JsonResponse(list(cities.values('id', 'name')), safe=False)
Autobuddy/forms.py
from django import forms
from autobuddyapp.models import Make, Model, Car
class ModelCreationForm(forms.ModelForm):
class Meta:
model = Car
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['model'].queryset = Model.objects.none()
if 'make' in self.data:
try:
make_id = int(self.data.get('make'))
self.fields['model'].queryset = Model.objects.filter(make_id=make_id).order_by('name')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and fallback to empty City queryset
elif self.instance.pk:
self.fields['model'].queryset = self.instance.model.make_set.order_by('name')
First problem is right on the first line of your script:
You are trying to capture change events on the wrong select, it should be on
id_make. There is also problems in the response method and in the way you are trying to update the selector.Response should be an JSON object. And to update the selector we need to create
optionsand add to the specific element, in this caseid_model. (Also, we need to clear before populating it again)views.py
template.html
Everything else, remains untouched.