Django Forms.ValidationError未显示在模板中,并且提交不起作用

时间:2019-02-25 03:04:36

标签: django django-forms django-templates

在我的Django应用程序中,我有一个与我们联系的模板,其中包含以下字段:公司名称,联系电话,电子邮件地址。

我已经定义了def clean()来验证电子邮件地址和电话号码,如下所示:

class ContactForm(forms.Form):
    def clean(self):
        super(ContactForm, self).clean()
        email_address = self.cleaned_data.get('email_address')
        contact_no = self.cleaned_data.get('contact_no')

        if validate_email(email_address):
            pattern = re.compile('^[2-9]\\d{9}$')
            if bool(pattern.match(contact_no)):
                return self.cleaned_data
            else: # error not displayed
                raise forms.ValidationError(
                    "Please enter a valid phone number")
        else: # error not displayed
            raise forms.ValidationError(
                "Please enter a valid email address")
        return self.cleaned_data

在“ contact_us”模板中,我也正确呈现了错误:

<form method="post" action="{% url 'contact' %}">
    {% csrf_token %}
    {{contact_form.as_p}
    <input type="submit" value="Submit">
</form>

{% if contact_form.errors %}
    {% for field in contact_form %}
        {% for error in field.errors %}
        <div class="alert alert-danger">
            <strong>{{ error|escape }}</strong>
        </div>
        {% endfor %}
    {% endfor %}
{% endif %}

在views.py中,即使表单有效并且成功发送了电子邮件,表单也不会在模板上再次呈现(作为新表单)。

 def contact(request):
     contact_form = ContactForm()

     if request.method == 'POST':
        contact_form = ContactForm(request.POST)
        if contact_form.is_valid():
            company_name = contact_form.cleaned_data.get('company_name')
            contact_no = contact_form.cleaned_data.get('contact_no')
            email_address = contact_form.cleaned_data.get('email_address')

            # send mail code

            contact_form.save()
            contact_form = ContactForm()
            return render(request, './mysite/contact_us.html', {
                'contact_form': contact_form, 'successful_submit': True})
     return render(request, './mysite/contact_us.html', {
         'contact_form': contact_form,
     })

请帮助!谢谢。

1 个答案:

答案 0 :(得分:1)

您正在从clean()引发ValidationError,因此该错误存储在form.non_field_errors-which you are not displaying中,因此显然您看不到它们。

documented solution将改用self.add_error(<fieldname>, <msg>)

但是:

  

但是我要在两个字段上执行验证,因此我使用了通用的clean()方法,而不是两个单独的clean_field()方法。

form.clean()用于交叉验证-验证两个相互依赖的字段。在您的示例中,这两个字段之间绝对没有依赖关系,您不需要电子邮件的值来验证电话号码,也不需要电话号码来验证电子邮件。 IOW,您应该真正使用不同的clean_field方法。

请注意,即使您进行了交叉验证,也可以(并且应该)仍然使用clean_field方法来进行单独验证。在您的情况下,您应该使用validate_email_address方法来验证电子邮件本身(或仅使用form.EmailField FWIW),而在clean()中,只需检查电子邮件是否已验证(如果未验证,会在self._errors['email_address']中找到一些错误。

在我们讨论的同时,您的代码还有很多其他问题。在这里:

    if validate_email(email_address):
        pattern = re.compile('^[2-9]\\d{9}$')
        if bool(pattern.match(contact_no)):
            return self.cleaned_data
        else: # error not displayed
            raise forms.ValidationError(
                "Please enter a valid phone number")
    else: # error not displayed
        raise forms.ValidationError(
            "Please enter a valid email address")
    return self.cleaned_data

1 /以这种方式预编译正则表达式完全没有用。您可以在模块的顶层对其进行预编译,以便仅对其进行一次编译(至少每个进程一次),或者根本不编译,而使用re函数,即if re.match(r"your expression here", your_variable)-re模块不仅会编译该表达式,还将对其进行缓存以供将来重用。

2 / if bool(pattern.match(contact_no))->对bool的调用是多余的,Python仍会这样做。

3 /,但是Django已经有一个正则表达式验证器,因此您应该使用它。

4 /控制流程毫无用处的复杂,最后的return语句实际上将永远不会执行。这个:

    if validate_email(email_address):
        pattern = re.compile('^[2-9]\\d{9}$')
        if bool(pattern.match(contact_no)):
            return self.cleaned_data
        else: # error not displayed
            raise forms.ValidationError(
                "Please enter a valid phone number")
    else: # error not displayed
        raise forms.ValidationError(
            "Please enter a valid email address")
通过提早退出,

将更具可读性:

    if not validate_email(email_address):
        raise forms.ValidationError(
            "Please enter a valid email address"
            )

    pattern = re.compile('^[2-9]\\d{9}$')
    if not pattern.match(contact_no)):
        raise forms.ValidationError(
            "Please enter a valid phone number"
            )

    return self.cleaned_data

5 /,但这仍然是错误的,因为验证将在检测到的第一个错误时停止-您希望一次捕获尽可能多的验证错误,以便用户不必阅读错误消息,而更正一个字段,重新提交,找到另一个可能是首次检测到的错误,修复该问题,然后重新提交等。好吧,除非您的目标是使用户难以接受,否则他会给出当然,尝试使用您的网站。

6 /您的视图代码也是双重错误。首先,您应该在发送邮件之前保存表单(我假设为ModelForm),因此,如果出现任何问题,请不要丢失数据,然后正如丹尼尔已经提到的,您应该始终重定向成功的帖子(read this