我的申请中有多个依赖下拉菜单。要添加新记录,表单将按预期工作;例如,您选择一个
Country
并将加载该 State
的 Country
对象列表,然后选择一个 State
并将加载该 Suburb
的 State
对象。您保存记录,它已正确保存所有字段,您查看记录,所有信息都可以按预期查看。
我遇到的问题是当我想更改/更新记录时。实例化的
SuburbForm
被告知首先加载 State
的空白下拉列表,并在设置父对象 load_dropdowns
时调用函数 Country
。调用 load_dropdowns
的操作似乎不会在更新表单中发生,相反,即使我尝试重新选择父级,它也只是保持空白。
如果我更改实例化表单以加载所有对象而不是空白下拉列表,则更新表单会正确填写该字段,但这意味着添加新表单和更新表单现在会加载所有对象而不是过滤列表。
模型.py
from django.db import models
class Country(models.Model):
item_name = models.CharField(verbose_name="Country")
class State(models.Model):
item_name = models.CharField(verbose_name="State")
state_in_country = models.ForeignKey(Country, on_delete=models.SET_NULL, verbose_name="Country", blank=True, null=True)
class Suburb(models.Model):
item_name = models.CharField(verbose_name="Suburb")
suburb_in_country = models.ForeignKey(Country, on_delete=models.SET_NULL, verbose_name="Country", blank=True, null=True)
suburb_in_state = models.ForeignKey(State, on_delete=models.SET_NULL, verbose_name="State", blank=True, null=True)
forms.py
from django import forms
from .models import Country, State, Suburb
class CountryForm(forms.ModelForm):
class Meta:
model = Country
fields = [
'item_name'
]
class StateForm(forms.ModelForm):
class Meta:
model = State
fields = [
'item_name',
'state_in_country'
]
class SuburbForm(forms.ModelForm):
# separately define fields for dependent dropdowns
suburb_in_country = forms.ModelChoiceField(queryset=Country.objects.filter(deleted=False),widget=forms.Select(attrs={"hx-get": "load_states_for_suburbform/", "hx-target": "#id_suburb_in_state"}),label="Country")
# THE FOLLOWING VARIABLE RESULTS IN A BLANK DROPDOWN LIST WHICH CHANGES TO A FILTERED LIST ON ADD NEW FORM BUT REMAINS BLANK ON UPDATE FORM - SEE __init__ BELOW
suburb_in_state = forms.ModelChoiceField(queryset=State.objects.none(),label="State")
class Meta:
model = Suburb
fields = [
'item_name',
'suburb_in_country',
'suburb_in_state'
]
def __init__(self, *args, **kwargs):
super(SuburbForm, self).__init__(*args, **kwargs)
# handle input from dependent dropdowns
if 'suburb_in_country' in self.data:
suburb_in_country = int(self.data.get("suburb_in_country"))
self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=suburb_in_country)
views.py
from django.shortcuts import render,redirect,get_object_or_404
from .forms import *
from .models import *
...
def update(request, id, item):
item = str_to_class(item)
page_title = 'Update ' + item._meta.verbose_name
instance = get_object_or_404(item, id=id)
if request.method == 'POST':
form = str_to_class(item._meta.verbose_name.strip() + 'Form')(request.POST, instance=instance)
if form.is_valid():
form.save()
return redirect(item._meta.list_view)
else:
form = str_to_class(item._meta.verbose_name.strip() + 'Form')(instance=instance)
context = {'form':form,
'title': page_title,
'list_view': item._meta.list_view}
return render(request, 'create.html', context)
...
# Load data for dropdowns that depend on the choice of parent item
# requires model name (item) and the parent field to filter on (parent_field)
def load_dropdowns(request, item, parent_field):
parent_id = 0 if request.GET.get(parent_field) in (None, '') else request.GET.get(parent_field)
if parent_id == 0:
# parent item has not yet been chosen (or blank has been selected)
return render(request, "emptydropdown.html")
if item == State:
# parent item of State is Country
# show only states belonging to the chosen country
items = State.objects.filter(state_in_country_id=parent_id, deleted=False).order_by('item_name')
if item == Suburb:
# parent item of Suburb is State
# show only suburbs belonging to the chosen state
items = Suburb.objects.filter(suburb_in_state_id=parent_id, deleted=False).order_by('item_name')
return render(request, 'dependentdropdown.html', context={'items': items})
...
def load_states_for_suburbform(request):
return load_dropdowns(request, State, 'suburb_in_country')
解决方案是在
SuburbForm
末尾附加一个if语句:
class SuburbForm(forms.ModelForm):
# separately define fields for dependent dropdowns
suburb_in_country = forms.ModelChoiceField(queryset=Country.objects.filter(deleted=False),widget=forms.Select(attrs={"hx-get": "load_states_for_suburbform/", "hx-target": "#id_suburb_in_state"}),label="Country")
# THE FOLLOWING VARIABLE RESULTS IN A BLANK DROPDOWN LIST WHICH CHANGES TO A FILTERED LIST ON ADD NEW FORM BUT REMAINS BLANK ON UPDATE FORM - SEE __init__ BELOW
suburb_in_state = forms.ModelChoiceField(queryset=State.objects.none(),label="State")
class Meta:
model = Suburb
fields = [
'item_name',
'suburb_in_country',
'suburb_in_state'
]
def __init__(self, *args, **kwargs):
super(SuburbForm, self).__init__(*args, **kwargs)
# handle input from dependent dropdowns
if 'suburb_in_country' in self.data:
suburb_in_country = int(self.data.get("suburb_in_country"))
self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=suburb_in_country)
elif self.instance.pk:
self.fields['suburb_in_state'].queryset = State.objects.filter(state_in_country=self.instance.suburb_in_country)