我们正在使用Django 1.4.3和django-cities-light 2.1.5来创建我们的网站。我们使用表单的__init__
方法来更新区域和城市列表。问题是,如果用户选择了一个城市并且表单未验证,我想将区域选择更改为所选城市的区域。这是代码:
def __init__(self, instance, *args, **kwargs):
super(ContentItemModelForm, self).__init__(*args, instance=instance, **kwargs)
....
....
....
country_id = None
if ((hasattr(self, "initial")) and ("country_id" in self.initial)):
country_id = int(self.initial['country_id']) if self.initial['country_id'] else None
elif ((hasattr(self, "data")) and (u'country_id' in self.data)):
country_id = int(self.data[u'country_id']) if self.data[u'country_id'] else None
region_id = None
if ((hasattr(self, "initial")) and ("region_id" in self.initial)):
region_id = int(self.initial['region_id']) if self.initial['region_id'] else None
elif ((hasattr(self, "data")) and (u'region_id' in self.data)):
region_id = int(self.data[u'region_id']) if self.data[u'region_id'] else None
city_id = None
if ((hasattr(self, "initial")) and ("city_id" in self.initial)):
city_id = int(self.initial['city_id']) if self.initial['city_id'] else None
elif ((hasattr(self, "data")) and (u'city_id' in self.data)):
city_id = int(self.data[u'city_id']) if self.data[u'city_id'] else None
if (city_id):
city_obj = City.objects.get(geoname_id=city_id)
country_id = city_obj.country_id
region_id = city_obj.region_id
# Set current values of country_id and region_id - commented (not working).
#self.fields['country_id'].initial = country_id
#self.fields['region_id'].initial = region_id
self.fields['region_id'].choices = [("", "(None)", ),]+[(obj.id, obj.name) for obj in Region.objects.filter(country_id=country_id).order_by("name")]
if (region_id):
self.fields['city_id'].choices = [("", "(None)", ),]+[(obj.geoname_id, obj.name) for obj in City.objects.filter(country_id=country_id, region_id=region_id).order_by("name")]
else:
self.fields['city_id'].choices = [("", "(None)", ),]+[(obj.geoname_id, obj.name) for obj in City.objects.filter(country_id=country_id).order_by("name")]
检查city_id,region_id和country_id的当前值的代码太长,我找不到缩短它的方法。如果未注释,则注释行(self.fields['country_id'].initial = country_id
和self.fields['region_id'].initial = region_id
)不起作用 - 如果仅选择国家/地区和城市,则所选区域为“(无)”(如果表单不验证)。如果表单有效,那么我们根据所选城市分配country_id和region_id值(国家和地区不会保存到数据库中)。
以下是城市验证:
def clean_city_id(self):
cleaned_data = self.cleaned_data
country_id = cleaned_data['country_id'] if (cleaned_data.has_key('country_id')) else None
region_id = cleaned_data['region_id'] if (cleaned_data.has_key('region_id')) else None
city_id = cleaned_data['city_id'] if (cleaned_data.has_key('city_id')) else None
if (not(city_id)):
if (region_id):
error_message = "If you select a country and a state/region, you must select a city."
self._errors["city_id"] = self.error_class([error_message])
raise forms.ValidationError(error_message)
elif (country_id):
error_message = "If you select a country, you must select a city."
self._errors["city_id"] = self.error_class([error_message])
raise forms.ValidationError(error_message)
return city_id
您知道我们如何为国家和地区分配正确的值吗?
(编辑):我们希望在选择城市后的HTML中将selected="selected"
放在正确的区域中,而不是在第一个“(无)”区域中(如果用户未选择区域)。我们使用AJAX在用户选择新的国家或地区后更新列表,但我们不希望在加载表单后立即使用AJAX。
谢谢, URI。
答案 0 :(得分:0)
我建议用另一种方法来解决问题。替代“手动”设置用户值 - 让用户自己做。像这样:
1)选择更改事件的触发形式GET
2)在那些事件中,回调将表单数据传递给视图 - 就像你使用POST一样。只是做GET请求而不是POST请求。
3)在视图中,只需将request.GET作为第一个参数传递而不是request.POST
4)让你现有的逻辑在形式init方法中发挥作用。
5)返回表单模板,其中包含正确有效的视图选项
6)用新表格切换现有表格。
无论如何我会怎么做。无需分配任何东西。让用户在刷新表单后做出选择。