django - Django forms.ValidationError 未显示在模板中并且提交不起作用
问题描述
在我的 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,
})
解决方案
您正在从 ValidationError 提高clean()
,因此错误存储在其中form.non_field_errors
-您没有显示,因此很明显您看不到它们。
一个记录在案的解决方案是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),因此如果出现任何问题,您不会丢失数据,然后正如 Daniel 已经提到的,您应该始终在成功发布后重定向(阅读此内容为什么)
推荐阅读
- kerberos - 通过 Kerberos 配置将 Corda 节点连接到 PostgreSql
- regex - 如何查找和替换除数字之外的所有内容?
- django - Django markdown show_preview 功能抛出错误
- sql-server - 有人可以帮助将此 SQL Server“更新语句”转换为 Oracle
- swagger - 代码生成的招摇“必需”与“可空”
- mongodb - 插入中的MongoDB子查询
- angular - 启用常春藤时的角度循环依赖
- r - 需要删除字符串,只保留 R 中的最后两个字符
- python - python WMI 屏幕亮度调节器出现错误 0x8004100c
- java - 列出 java 程序的简单目录无法编译 un JDK 1.7