无法在Django中实现动态下拉列表

时间:2016-07-11 14:37:35

标签: javascript jquery python django

我需要实现两个下拉列表,秒的值取决于第一个的选择。

我能够在后端实现它,但我正在努力在前端进行,更具体地说是使用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中实现这一点会非常困难。

我想避免使用第三方应用或模块来做这个简单的事情,我想用一种正确的方法来做到这一点(即最好的方式),所以任何想法都会非常有价值。

2 个答案:

答案 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 }};