如何在Django中更改表单值?

时间:2013-11-18 13:48:37

标签: django django-forms

我们正在使用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_idself.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。

1 个答案:

答案 0 :(得分:0)

我建议用另一种方法来解决问题。替代“手动”设置用户值 - 让用户自己做。像这样:

1)选择更改事件的触发形式GET

2)在那些事件中,回调将表单数据传递给视图 - 就像你使用POST一样。只是做GET请求而不是POST请求。

3)在视图中,只需将request.GET作为第一个参数传递而不是request.POST

4)让你现有的逻辑在形式init方法中发挥作用。

5)返回表单模板,其中包含正确有效的视图选项

6)用新表格切换现有表格。

无论如何我会怎么做。无需分配任何东西。让用户在刷新表单后做出选择。