在我的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,
})
请帮助!谢谢。
答案 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)