【问题标题】:django - must have at least one form field filled indjango - 必须至少填写一个表单字段
【发布时间】:2014-10-16 22:30:52
【问题描述】:

我正在学习使用 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>

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

【问题讨论】:

  • 您可以尝试从 javascript 端解决此问题。在您发送 ajax/form 请求之前,只需要求用户至少填写其中一项即可。

标签: python django validation django-forms


【解决方案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

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

【讨论】:

    【解决方案2】:

    可能有一些 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 上,这将立即返回一个列表,但如果你在 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]
    

    不过,我从来没有用表单来做到这一点。是否真的有必要在覆盖的 clean 方法上删除它们?这在视图中不能更好地处理吗?我会留给其他人来回答。

    之后,您可以返回您的表格。

    编辑

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

    您的原始代码几乎缺少的是 DRY 原则:“不要重复自己。”尝试在你正在做的事情中找到共同的模式,并利用这些模式来发挥你的优势。如果您在三个或四个位置编写相同的字符串数组,那就有问题了。将它们保存到列表中并迭代它们。要阅读的代码要少得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-07
      • 2020-03-31
      • 2017-02-07
      • 1970-01-01
      • 2021-09-29
      • 2021-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多