Django Динамическое выпадающее меню не заполняется
Я работаю над проектом, в котором стоит задача реализовать динамическое выпадающее меню, в котором варианты выбора в меню будут меняться в зависимости от значения, которое пользователь выбирает из предыдущего выпадающего меню.
У меня есть первое выпадающее меню, заполненное значениями ключей name
в JSON ниже (Network 1
, Network 2
и т.д.). Моя цель состоит в том, чтобы второе выпадающее меню заполнялось списком значений zone
, которые соответствуют значению name
, выбранному пользователем в первом выпадающем меню.
Итак, если пользователь выбирает Network 1
из первого выпадающего списка, то второй выпадающий список будет содержать network.1.private.zone
в качестве единственного варианта. Если пользователь выберет Network 2
из первого выпадающего списка, то второй выпадающий список будет содержать network.2.private.zone
в качестве единственного варианта, и так далее.
Отчасти благодаря этому руководству, я довольно сильно продвинулся в этом деле. Я вижу, как AJAX-запрос выполняется в браузере, и значения url
и networkId
кажутся правильными, когда я console.log
передаю их в браузер. Но я не могу понять, почему динамическое выпадающее меню не заполняется. Вот скриншот того, как выглядит страница:
Примечательно, что в моем проекте нет никаких моделей; скорее, все данные, с которыми я работаю, хранятся в файле JSON, ссылка на который приведена выше и показана ниже. Что я упускаю?
Ниже приводится код:
Вот файл JSON:
[
{
"name": "Network 1",
"onboard": {
"format": "network",
"base": "172.27.22.0",
"mask": "255.255.255.0",
"zones": ["network.1.onboard.zone"]
},
"private": {
"format": "network",
"base": "172.24.16.0",
"mask": "255.255.252.0",
"zones": ["network.1.private.zone"]
},
"public": {
"format": "network",
"base": "128.237.78.0",
"mask": "255.255.255.0",
"zones": ["network.1.public.zone"]
}
},
{
"name": "Network 2",
"onboard": {
"format": "network",
"base": "172.27.23.0",
"mask": "255.255.255.0",
"zones": ["network.2.onboard.zone"]
},
"private": {
"format": "network",
"base": "172.24.234.0",
"mask": "255.255.254.0",
"zones": ["network.2.private.zone"]
},
"public": {
"format": "network",
"base": "172.24.234.0",
"mask": "255.255.254.0",
"zones": ["network.2.public.zone"]
}
},
...
]
utils.py (Файл JSON, приведенный выше, упоминается здесь как WIRED_GROUPS)
...
def return_zones_by_network(network_name, network_group=WIRED_GROUPS, private=True):
"""
Helper function that will eventually be used to construct the dynamic dropdown menu.
**** WIRED_GROUPS is the JSON file referenced earlier in this post ****
"""
network_zones = []
for network in network_group:
if network['name'] == network_name:
if private:
for zone in network['private']['zones']:
network_zones.append(zone)
else:
for zone in network['public']['zones']:
network_zones.append(zone)
return network_zones
...
forms.py
class WiredRegistrationForm(Form):
def __init__(self, groups, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['group'].choices = ((0, '---------',),)
self.fields['group'].choices += tuple(
(i+1, groups[i],) for i in range(len(groups))
)
self.fields['hostname_zones'].queryset = ((0, '---------',),)
network = ChoiceField(
# choices=wired_network_choices,
choices=wired_network_choices,
widget=Select(attrs={'class': 'form-control'})
)
hostname = CharField(
label='Hostname',
max_length=63,
error_messages={'incomplete': 'Enter a hostname.'},
validators=[HOSTNAME_VALIDATOR],
widget=TextInput(attrs={
'autocomplete': 'off',
'autocapitalize': 'off'
})
)
# this is the field that needs to be dynamically populated.
hostname_zones = ChoiceField(
choices=[],
widget=Select(attrs={'class': 'form-control'})
)
mac_address = MACAddressField(label="MAC address")
group = ChoiceField(
widget=Select(attrs={'class': 'form-control'}),
)
views.py
urls.py
app_name = 'hosts'
urlpatterns = [
...
url(
r'^register/$',
views.register,
name='register'
),
url(
r'^register/wired',
views.register_wired,
name='register_wired'
),
url(
r'^register/wired/load-hostname-zones',
views.load_hostname_zones,
name='register_wired_load_hostname_zones'
),
...
]
/templates/hosts/register/wired.html
/templates/hosts/register/host_zones_dropdown_list_options.html
{# This is only used to compose the tiny bit of HTML that is the hostname zone dropdown menu #}
<option value="">---------</option>
{% for hostname_zone in hostname_zones %}
{#<option value="{{ network_zones.index(network_zone) }}">{{ network_zone }}</option>#}
<option value="{{ hostname_zone.pk }}">{{ hostname_zone.name }}</option>
{% endfor %}
Итак, я разобрался с этим. Проблема заключалась в несоответствии между моей вспомогательной функцией в файле utils.py, которую можно увидеть здесь:
def return_zones_by_network(network_name, network_group=WIRED_GROUPS, private=True):
"""
Helper function that will eventually be used to construct the dynamic dropdown menu.
**** WIRED_GROUPS is the JSON file referenced earlier in this post ****
"""
network_zones = []
for network in network_group:
if network['name'] == network_name:
if private:
for zone in network['private']['zones']:
network_zones.append(zone)
else:
for zone in network['public']['zones']:
network_zones.append(zone)
return network_zones # returns a list, not a dict
и крошечный шаблон в /templates/hosts/register/host_zones_dropdown_list_options.html, который можно увидеть здесь:
<option value="">---------</option>
{% for hostname_zone in hostname_zones %}
<option value="{{ hostname_zone.pk }}">{{ hostname_zone.name }}</option> # this line here
{% endfor %}
В шаблоне я ссылался на свойства каждого hostname_zone
(pk и name), когда в действительности каждый hostname_zone
является строкой из списка. Наверное, я немного удивлен, что я не получил что-то вроде ошибки атрибута при ссылке на несуществующие свойства, но теперь выпадающее меню динамически заполняется, как и должно.
Ниже приведен исправленный шаблон. Надеюсь, это поможет кому-нибудь еще на этом пути:
<option value="">---------</option>
{% for hostname_zone in hostname_zones %}
<option value="">{{ hostname_zone }}</option>
{% endfor %}