我需要实现两个下拉列表,秒的值取决于第一个的选择。
我能够在后端实现它,但我正在努力在前端进行,更具体地说是使用javascript!
countries = Country.objects.filter(Enabled=True)
citiesByCountry = {}
for country in countries:
citiesInCountry = City.objects.filter(Enabled=True, Country=country)
cities = []
for city in citiesInCountry:
cities.append(city.Name)
citiesByCountry[country.Name] = cities
context = {'citiesByCountry': citiesByCountry}
return render(request, 'index.html', context)
所以我有以下结构:
'Country':['City1', 'City2']
这是HTML:
<div class="form-group col-md-4">
<select class="form-control" onchange="test(this.value)" id="sel1">
{% for country in citiesByCountry %}
<option value="{{ country }}">{{ country }}</option>
{% endfor %}
</select>
</div>
<div class="form-group col-md-4">
<select class="form-control" id="cities">
</select>
</div>
所以我添加了以下javascript:
<script>
var country_objs = {};
{% for country, cities in citiesByCountry.items %}
country_objs['{{country|escapejs}}'] = '{{cities|escapejs}}';
{% endfor %}
</script>
<script type="application/javascript">
function test(country) {
var $cities_select = $("#cities");
$(country_objs[country]).each(function(){
$cities_select.append('<option>' + this + '<\option>');
});
}
</script>
第二个下拉列表永远不会填充,但是当我打印country_objs
的内容时,这样:console.log(country_objs[country]);
我得到以下内容:
['City1', 'City2', 'City3']
哪个是正确的,但.each
函数不会遍历项目。我认为问题是以上不是一个合适的数组而是一个字符串,但仍然无法理解为什么。
请注意,我收到以下错误:
jquery.min.js:2 Uncaught Error: Syntax error, unrecognized expression: ['City1', 'City2', 'City3']
不幸的是,无论我尝试什么都行不通,我无法想象在Django中实现这一点会非常困难。
我想避免使用第三方应用或模块来做这个简单的事情,我想用一种正确的方法来做到这一点(即最好的方式),所以任何想法都会非常有价值。
答案 0 :(得分:1)
有两种解决方案:
解决方案1:
使用for循环:
country_objs['{{country|escapejs}}'] = [{% for city in cities %}"city",{% endfor %}];
解决方案2:
切换线路:
citiesByCountry[country.Name] = cities
有:
citiesByCountry[country.Name] = json.dumps(cities)
编码为json,然后在模板中:
country_objs['{{country|escapejs}}'] = {{cities|safe}};
关于解决方案2的Obs:
你不能在变量
周围加上单引号'{{cities|safe}}';
在第二个解决方案中,或者当您添加列表['City1', 'City2', 'City3']
时,您将拥有:
'['City1', 'City2', 'City3']'
答案 1 :(得分:0)
我认为您要删除要在JavaScript中解析的部分的|escapejs
过滤器。您甚至可能会发现需要|safe
,但在考虑之前,您应该确定您可以控制输出的内容。
var country_objs = {};
{% for country, cities in citiesByCountry.items %}
country_objs['{{country|escapejs}}'] = {{cities|safe}};
{% endfor %}
对于更新部分,这应该有效:
function updateCities(country) {
var $cities_select = $("#cities");
$(country_objs[country]).each(function(key, value) {
$('#cities').append($("<option></option>")
.attr("value",key)
.text(value));
});
}
$('#sel1').change(function() {
updateCities(this.value);
});
部分归功于此答案https://stackoverflow.com/a/171007/823020。
上面缺少初始设置,您可以使用模板或JavaScript。对于JavaScript,您可以插入另一个updateCities($('#cities).val());
。
上述内容每次都会附加,而不是将选项重置为空列表。这留给读者练习。
建议1:你没有讨论过这个问题,但你最初的查询会做得更好:
# the following may differ based on your foreign key's related_name attribute
countries = Country.objects.filter(Enabled=True).select_related('city_set')
for country in countries:
citiesInCountry = country.city_set.values_list('name', flat=True)
这都是一个查询。但是,您需要重新考虑“活跃”标志,或者如果您仍然需要它,如何实现这一目标。
建议2:说实话,将它包装在json中可能会更好。在您看来:
import json
countries_json = json.dumps(citiesByCountry)
然后在模板中:
var country_objs = {{ citiesByCountry|safe }};