I am using django and postgresql. I'm dealing with a 3-way dependent drop-down list. After adding the country selection, the province area is automatically updated depending on the selected country. After selecting a province, the county field opens only when the page is refreshed. I would be glad if you help me in this regard.
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class District(models.Model):
city = models.ForeignKey(City, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateField(null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
district = models.ForeignKey(District, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
from django import forms
from .models import Person, Country, City, District
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ('name', 'birthdate', 'country', 'city', 'district')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['city'].queryset = City.objects.none()
if 'country' in self.data:
try:
country_id = int(self.data.get('country'))
self.fields['city'].queryset = City.objects.filter(country_id=country_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['city'].queryset = self.instance.country.city_set.order_by('name')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['district'].queryset = District.objects.none()
if 'city' in self.data:
try:
city_id = int(self.data.get('city'))
self.fields['district'].queryset = District.objects.filter(city_id=city_id).order_by('name')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and fallback to empty District queryset
elif self.instance.pk:
self.fields['district'].queryset = self.instance.city.district_set.order_by('name')
def load_cities(request):
country_id = request.GET.get('country')
cities = City.objects.filter(country_id=country_id).order_by('name')
return render(request, 'neighbor/city_dropdown_list_options.html', {'cities': cities})
def load_districts(request):
city_id = request.GET.get('city')
districts = District.objects.filter(city_id=city_id).order_by('name')
return render(request, 'neighbor/district_dropdown_list_options.html', {'districts': districts})
<h2>Person Form</h2>
<form method="post" id="personForm" data-cities-url="{% url 'ajax_load_cities' %}" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Save</button>
<a href="{% url 'person_changelist' %}">Nevermind</a>
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#id_country").change(function () {
var url = $("#personForm").attr("data-cities-url");
var countryId = $(this).val();
$.ajax({
url: url,
data: {
'country': countryId
},
success: function (data) {
$("#id_city").html(data);
}
});
});
$("#id_city").change(function () {
var url = $("#personForm").attr("data-districts-url");
var cityId = $(this).val();
$.ajax({
url: url,
data: {
'city': cityId
},
success: function (data) {
$("#id_district").html(data);
}
});
});
</script>
I'm referring to the example here.
https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html
To create a dropdown in Python Django model form, we can create a char field with the choices argument set to a tuple of choices in a model class. Then we can set the model class as the model for the form. to add the color field to the MyModel model class.
In your templates.html file, you are calling the same URL hence the same view for country and city fields change. you need to make a new URL to handle the request in load_district view.
make the following changes
$("#id_city").change(function () {
var url = $("#personForm").attr("data-districts-url");
var cityId = $(this).val();
$.ajax({
url: '{% url 'ajax_load_districts' %}',
data: {
'city': cityId
},
success: function (data) {
$("#id_district").html(data);
}
});
});
you don't need to modify init() method twice, just remove these 2 lines from froms.py. (line number 22 and 23)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
add a new URL for handling ajax request for district
path('ajax/load-district/', views.load_districts, name='ajax_load_districts'),
you can clone this example, i have used Country, City, Vanue ... https://github.com/masbhanoman/django_3way_chained_dropdown_list
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With