django - 必须至少填写一个表单字段

时间:2014-08-23 01:46:14

标签: python django validation django-forms

我正在学习使用Django 1.4(我会在1.7发布后立即进行升级)。

我有一个测试表单,其中我已将所有字段标记为required = False,但我需要让用户在表单上输入至少一个字段。只要输入至少一个条目,输入哪个字段无关紧要。

我确实有一个可行的解决方案,但我认为这可以做得更好,所以我希望有一个对django更好理解的人可以向我展示更好的解决方案。

这是我的型号代码:

....
nationality_visa_country_of_birth = models.TextField(null=True, blank=True)
nationality_visa_citizenship = models.TextField(null=True, blank=True)
nationality_visa_residency = models.TextField(null=True, blank=True)
nationality_visa_work_visa = models.TextField(null=True, blank=True)
nationality_visa_study_visa = models.TextField(null=True, blank=True)
nationality_visa_specialist_visa = models.TextField(null=True, blank=True)
nationality_visa_other_visa = models.TextField(null=True, blank=True)
nationality_visa_current_valid_passport_display_type = models.PositiveIntegerField(default=0)
nationality_visa_multiple_passports = models.BooleanField(default=False)
nationality_visa_passport_nationality = models.TextField(null=True, blank=True)
nationality_visa_timestamp_added = models.DateTimeField(auto_now_add=True, auto_now=False)
nationality_visa_timestamp_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
....

这是我的表单代码:

nationality_visa_country_of_birth = forms.CharField(label=_('Country of Birth'), max_length=250, required=False)
nationality_visa_citizenship = forms.CharField(label=_('Citizenship'), max_length=250, required=False)
nationality_visa_residency = forms.CharField( label=_('Residency'), max_length=250, required=False)
nationality_visa_work_visa = forms.CharField( label=_('Work Visa'), max_length=250, required=False)
nationality_visa_study_visa = forms.CharField( label=_('Student Visa'),max_length=250, required=False)
nationality_visa_specialist_visa = forms.CharField(label=_('Specialist Visa'), max_length=250, required=False)
nationality_visa_other_visa = forms.CharField(label=_('Other Visa'), max_length=250, required=False)
nationality_visa_current_valid_passport_display_type = forms.TypedChoiceField(coerce=int, label=_('Current Valid Passport'), choices=[(x, x) for x in range(0, 3)], required=False)
nationality_visa_multiple_passports = forms.BooleanField( label=_('Multiple Passports'), required=False, help_text=_("Select this option if you're going to enter multiple passport details into the field below."))
nationality_visa_passport_nationality = forms.CharField( label=_('Nationality of Passport(s)'), max_length=250, required=False)

以下是forms.py上的验证数据,它确实要求用户输入至少一个字段:

def clean(self):

    cd_nvdf = super(NationalityVisaDetailsForm, self).clean()

    if 'nationality_visa_country_of_birth' in cd_nvdf and len(cd_nvdf['nationality_visa_country_of_birth'].strip()) == 0:
        if 'nationality_visa_citizenship' in cd_nvdf and len(cd_nvdf['nationality_visa_citizenship'].strip()) == 0:
            if 'nationality_visa_residency' in cd_nvdf and len(cd_nvdf['nationality_visa_residency'].strip()) == 0:
                if 'nationality_visa_work_visa' in cd_nvdf and len(cd_nvdf['nationality_visa_work_visa'].strip()) == 0:
                    if 'nationality_visa_study_visa' in cd_nvdf and len(cd_nvdf['nationality_visa_study_visa'].strip()) == 0:
                        if 'nationality_visa_specialist_visa' in cd_nvdf and len(cd_nvdf['nationality_visa_specialist_visa'].strip()) == 0:
                            if 'nationality_visa_other_visa' in cd_nvdf and len(cd_nvdf['nationality_visa_other_visa'].strip()) == 0:
                                if 'nationality_visa_current_valid_passport_display_type' in cd_nvdf and cd_nvdf['nationality_visa_current_valid_passport_display_type'] == 0:
                                    if 'nationality_visa_passport_nationality' in cd_nvdf and len(cd_nvdf['nationality_visa_passport_nationality'].strip()) == 0:

                                        self._errors['nationality_visa_country_of_birth'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
                                        self._errors['nationality_visa_citizenship'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_residency'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_work_visa'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_study_visa'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_specialist_visa'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_other_visa'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_current_valid_passport_display_type'] = self.error_class([_(" ")])
                                        self._errors['nationality_visa_passport_nationality'] = self.error_class([_(" ")])

                                        del self.cleaned_data['nationality_visa_country_of_birth']
                                        del self.cleaned_data['nationality_visa_citizenship']
                                        del self.cleaned_data['nationality_visa_residency']
                                        del self.cleaned_data['nationality_visa_work_visa']
                                        del self.cleaned_data['nationality_visa_study_visa']
                                        del self.cleaned_data['nationality_visa_specialist_visa']
                                        del self.cleaned_data['nationality_visa_other_visa']
                                        del self.cleaned_data['nationality_visa_current_valid_passport_display_type']
                                        del self.cleaned_data['nationality_visa_passport_nationality']

    return cd_nvdf

目前,经过验证的表单突出显示了上述表单字段,但对于模板上的每个表单字段,以下html代码都插入到html代码中,因此在每个表单字段下都有一个额外的换行符:

<span class="help-inline">
    <strong>
        <br>
    </strong>
</span>

如何更好地编写验证码,以便用户输入至少一个表单字段和/或不包含上面显示的额外换行符?

2 个答案:

答案 0 :(得分:1)

这是工作解决方案:

    def clean(self):
    cd_nvdf = super(NationalityVisaDetailsForm, self).clean()

    if not any(
        cd_nvdf.get(x, '')
        for x in (
            'nationality_visa_country_of_birth',
            'nationality_visa_citizenship',
            'nationality_visa_residency',
            'nationality_visa_work_visa',
            'nationality_visa_study_visa',
            'nationality_visa_specialist_visa',
            'nationality_visa_other_visa',
            'nationality_visa_current_valid_passport_display_type',
            'nationality_visa_passport_nationality',
        )
    ):

        self._errors['nationality_visa_country_of_birth'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_citizenship'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_residency'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_work_visa'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_study_visa'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_specialist_visa'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_other_visa'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_current_valid_passport_display_type'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])
        self._errors['nationality_visa_passport_nationality'] = self.error_class([_("You must enter at least one Nationality & Visa Detail.")])

    return cd_nvdf

我希望这会对某人有所帮助。

答案 1 :(得分:0)

可能有一些Django细节可以帮到你,但我建议先考虑Python。

对于第一项任务,我认为你可能会受益于filter

首先,我们需要您要检查的值列表:

values_we_care_about = ['nationality_visa_country_of_birth'
                        'nationality_visa_citizenship'
                        'nationality_visa_residency'
                        'nationality_visa_work_visa',
                         etc.]

接下来,我们需要提炼出你用来将东西检查成一个简单函数的逻辑

def checking_stuff_function(value_cared_about):
    return value_cared_about in cd_nvdf and cd_nvdf.get(value_cared_about, None)

现在,我们可以使用此功能并使用它来过滤所有值(如果你在Python2上,这将立即返回一个列表,但是如果你&#39;在Python3上,你将得到一个生成器;我将假设Python2):

checked_values = filter(checking_stuff_function, values_we_care_about)

现在,我们可以查看有多少checked_values完成了这项工作。你可能已经看到了这种情况......

if len(checked_values) < 1:
   # There's an error!

现在,您只需要重置表单(因为之前我们使用了过滤器,为什么不在这里使用map?):

map(lambda val: del self.cleaned_data[val], values_we_care_about]
但是,我从来没有用表格做过。是否真的有必要在重写的清理方法上删除它们?在视图中可以更好地处理这个问题吗?我会把这个留给其他人来回答。

之后你可以退回你的表格。

修改

我忘记了你的错误。这也可以通过类似于我们在此处完成的方式完成,因此我不会尝试拼写出来。

您原来的代码缺失的原因是DRY原则:不要重复自己。&#39;尝试在您正在做的事情中找到常见模式,并将这些模式用于您的优势。如果你在三到四个地方写了相同的字符串数组,这就是一个问题。将它们保存到列表中,然后迭代它们。要阅读的代码要少得多。