验证Django中的动态选择字段

时间:2012-12-04 18:37:56

标签: django django-forms form-fields

我在Ubuntu 12.10上使用Django 1.4和Python 2.7。

我有一个表单,我需要动态填充一些下拉菜单(使用jQuery),但需要其中2个是必需的,而第3个是可选的。

我正在使用Tastypie来帮助API获取选项。基本上,第一个下拉列表中包含了学校的行业级代码。选择代码后,将为该代码的所有类别填充类别下拉列表。选择类别后,将为该代码和类别组合的所有子类别填充子类别下拉列表。

我可以要求代码下拉(它没有动态填充)。但是,我很难获得所需的类别下拉菜单。我基本上可以采用2条路线 - 前端验证或后端验证。我正在尝试使用后端验证,以便在需要时轻松创建进一步的验证。

以下是表格:

class SchoolProductForm(forms.ModelForm):
    cip_category = forms.ChoiceField(required=True,
                                     choices=(('', '----------'),))

    def __init__(self, *args, **kwargs):
        super(SchoolProductForm, self).__init__(*args, **kwargs)

        self.fields['short_description'].widget = TA_WIDGET
        self.fields['salary_info'].widget = TA_WIDGET
        self.fields['job_opportunities'].widget = TA_WIDGET
        self.fields['related_careers'].widget = TA_WIDGET
        self.fields['meta_keywords'].widget = TI_WIDGET
        self.fields['meta_description'].widget = TI_WIDGET
        self.fields['cip'].queryset = models.CIP.objects.filter(
            parent_id__isnull=True)


    class Meta:
        model = models.SchoolProduct
        exclude = ('campus',)

我试图覆盖clean方法。我试图创建一个特定于字段的clean方法。似乎都没有用。

以下各种变化:

def clean(self):
    super(SchoolProductForm, self).clean()
    if cip_category in self._errors:
        del self._errors['cip_category']
    if self.cleaned_data['cip_category'] == '----------':
        self._errors['cip_category'] = 'This field is required.'

    return self.cleaned_data

这会导致cip_category中没有cleaned_data的错误,这是有道理的,因为它没有验证。

我尝试过特定领域的变化:

def clean_cip_category(self):
    data = self.cleaned_data['cip_category']
    self.fields['cip_category'].choices = data

    return data

但是在页面上出现验证错误,说明我的选择不是可用选项之一。

我尝试创建动态字段类型(多种变体):

class DynamicChoiceField(forms.ChoiceField):
    def valid_value(self, value):
        return True

class SchoolProductForm(forms.ModelForm):
    cip_category = DynamicChoiceField(required=True,
                                      choices=(('', '----------'),))

但它接受----------作为有效选项(我不想要)并导致错误,因为ORM尝试匹配数据库中的----------值(它不会找到)。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我能够在ChoiceField中稍微改写一下方法来解决这个问题。

我将字段添加到表单中,并使用self.initial处理预填充:

class SchoolProductForm(forms.ModelForm):
    cip_category = common_forms.DynamicChoiceField(
        required=True, choices=(('', '----------'),))

    def __init__(self, *args, **kwargs):
        super(SchoolProductForm, self).__init__(*args, **kwargs)

        self.fields['short_description'].widget = TA_WIDGET
        self.fields['salary_info'].widget = TA_WIDGET
        self.fields['job_opportunities'].widget = TA_WIDGET
        self.fields['related_careers'].widget = TA_WIDGET
        self.fields['meta_keywords'].widget = TI_WIDGET
        self.fields['meta_description'].widget = TI_WIDGET
        self.fields['cip'].queryset = models.CIP.objects.filter(
            parent_id__isnull=True)

        # Get the top parent and pre-populate
        if 'cip' in self.initial:
            self.initial['cip'] = models.CIP.objects.get(
                pk=self.initial['cip']).top_parent()

    class Meta:
        model = models.SchoolProduct
        exclude = ('campus',)

DynamicChoiceField的位置:

class DynamicChoiceField(forms.ChoiceField):
    def valid_value(self, value):
        return True

然后,在视图中我添加了form_valid覆盖中的处理:

def form_valid(self, form):
    self.object = form.save(commit=False)

    # Handle the CIP code
    self.object.cip_id = self.request.POST.get('cip_subcategory')
    if self.object.cip_id == '':
        self.object.cip_id = self.request.POST.get('cip_category')

    self.object.save()