问题
I want to make a chained multiple choice field. I have working code for chained dropdown boxes below. I want to be able to choose more than one option at each level and have the next level return all records for each of the selected values. How can I make this happen? (my code is not very DRY, so appreciate any notes on that as well, but that is secondary)
models.py
class Nace_Level_1(models.Model):
code = models.CharField(max_length=1)
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=100)
notes = models.TextField()
def __str__(self):
return self.short_name
class Nace_Level_2(models.Model):
parent = models.ForeignKey(Nace_Level_1, on_delete=models.CASCADE)
code = models.CharField(max_length=2)
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=100)
notes = models.TextField()
def __str__(self):
return self.short_name
class Nace_Level_3(models.Model):
parent = models.ForeignKey(Nace_Level_2, on_delete=models.CASCADE)
code = models.CharField(max_length=4)
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=100)
notes = models.TextField()
def __str__(self):
return self.short_name
class Nace_Level_4(models.Model):
parent = models.ForeignKey(Nace_Level_3, on_delete=models.CASCADE)
code = models.CharField(max_length=5)
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=100)
notes = models.TextField()
def __str__(self):
return self.short_name
class Nace_Level_5(models.Model):
parent = models.ForeignKey(Nace_Level_4, on_delete=models.CASCADE, blank=True, null=True)
level_3 = models.ForeignKey(Nace_Level_3, on_delete=models.CASCADE, blank=True, null=True)
level_2 = models.ForeignKey(Nace_Level_2, on_delete=models.CASCADE, blank=True, null=True)
level_1 = models.ForeignKey(Nace_Level_1, on_delete=models.CASCADE, blank=True, null=True)
code = models.CharField(max_length=6)
name = models.CharField(max_length=200)
short_name = models.CharField(max_length=100)
notes = models.TextField()
def __str__(self):
return self.short_name
forms.py
class NaceForm(forms.ModelForm):
level_5 = forms.ChoiceField(label='', choices=Nace_Level_5.objects.none())
class Meta:
model = Nace_Level_5
fields = ('level_1','level_2','level_3','parent','level_5')
labels = {'level_1': (""),
'level_2': (""),
'level_3': (""),
'parent' : (""),}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['level_1'].queryset = Nace_Level_1.objects.all()
self.fields['level_2'].queryset = Nace_Level_2.objects.none()
self.fields['level_3'].queryset = Nace_Level_3.objects.none()
self.fields['parent'].queryset = Nace_Level_4.objects.none()
self.fields['level_1'].widget.attrs={'data-nace-url':'/ajax/load-level-2/'}
self.fields['level_2'].widget.attrs={'data-nace-url':'/ajax/load-level-3/'}
self.fields['level_3'].widget.attrs={'data-nace-url':'/ajax/load-level-4/'}
self.fields['parent'].widget.attrs={'data-nace-url':'/ajax/load-level-5/'}
urls.py
urlpatterns = [
path("industries/", views.NaceCreateView.as_view(), name="industries"),
path('ajax/load-level-2/', views.load_level_2, name="ajax_load_level_2"),
path('ajax/load-level-3/', views.load_level_3, name="ajax_load_level_3"),
path('ajax/load-level-4/', views.load_level_4, name="ajax_load_level_4"),
path('ajax/load-level-5/', views.load_level_5, name="ajax_load_level_5"),
]
views.py
class NaceCreateView(CreateView):
template_name = 'main/industries.html'
model = Nace_Level_5
form_class = NaceForm
def load_level_2(request):
level_1_id = request.GET.get('level_1')
level_2 = Nace_Level_2.objects.filter(parent=level_1_id)
return render(request, 'main/level_dropdown.html', {'levels': level_2})
def load_level_3(request):
level_2_id = request.GET.get('level_2')
level_3 = Nace_Level_3.objects.filter(parent=level_2_id)
return render(request, 'main/level_dropdown.html', {'levels': level_3})
def load_level_4(request):
level_3_id = request.GET.get('level_3')
level_4 = Nace_Level_4.objects.filter(parent=level_3_id)
return render(request, 'main/level_dropdown.html', {'levels': level_4})
def load_level_5(request):
level_4_id = request.GET.get('parent')
level_5 = Nace_Level_5.objects.filter(parent=level_4_id)
return render(request, 'main/level_dropdown.html', {'levels': level_5})
templates/main/industries.html
<div class='row'>
<div class='col'>
<form method="post" id="naceForm" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
</form>
</div>
</div>
<script>
$("#id_level_1").change(function () {
var url = $("#id_level_1").attr("data-nace-url");
var level_1_id = $(this).val();
$.ajax({
url: url,
data: {
'level_1': level_1_id
},
success: function (data) {
$("#id_level_2").html(data);
}
});
});
$("#id_level_2").change(function () {
var url = $("#id_level_2").attr("data-nace-url");
var level_2_id = $(this).val();
$.ajax({
url: url,
data: {
'level_2': level_2_id
},
success: function (data) {
$("#id_level_3").html(data);
}
});
});
$("#id_level_3").change(function () {
var url = $("#id_level_3").attr("data-nace-url");
var level_3_id = $(this).val();
$.ajax({
url: url,
data: {
'level_3': level_3_id
},
success: function (data) {
$("#id_parent").html(data);
}
});
});
$("#id_parent").change(function () {
var url = $("#id_parent").attr("data-nace-url");
var parent_id = $(this).val();
$.ajax({
url: url,
data: {
'parent': parent_id
},
success: function (data) {
$("#id_level_5").html(data);
}
});
});
</script>
templates/main/level_dropdown.html
<option value="">---------</option>
{% for level in levels %}
<option value="{{ level.id }}">{{ level.short_name }}</option>
{% endfor %}
来源:https://stackoverflow.com/questions/61373313/how-can-i-make-chained-multiple-choice-fields-in-django-with-jquery