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

Not able to implement a dynamic dropdown list in Django

本文关键字:实现 动态 下拉列表 Django      更新时间:2023-09-26

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

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

我想

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

有两种解决方案:

解决方案 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']'

我认为您想删除要在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 }};