Django集成SendGrid邮件验证时邮箱UniqueConstraint错误解决求助
问题根因
你定义的NewsletterUserForm作为ModelForm已经继承了模型email字段的unique=True校验规则,但你的视图逻辑完全没有使用表单做校验,直接从request.POST中取邮箱构造模型实例保存,重复邮箱直接触发了数据库层面的唯一约束报错。
修复步骤
1. 修改views.py中的newsletters视图逻辑
替换原有的POST处理逻辑,先走表单校验,校验通过后再保存数据、发送邮件,校验失败会自动把错误信息带回模板展示:
@csrf_exempt def newsletters(request): if request.method == 'POST': # 实例化表单,把POST数据传入 form = NewsletterUserForm(request.POST) # 触发表单校验,包含邮箱唯一性校验 if form.is_valid(): # 校验通过后构造模型实例,不直接提交到数据库 sub = form.save(commit=False) sub.conf_num = random_digits() sub.save() # 后面的发送邮件逻辑保持不变 message = Mail( from_email='pasiekaradosc@gmail.com', to_emails=sub.email, subject='Potwierdzenie Adresu Email w Newsletterze Pasieka Radość', html_content= "<h1>Dziękujemy za zapisanie się do newslettera Pasieka Radość!<h1> \<h2>Aby potwierdzić rejestrację newslettera</h2> \<h2><a href='{}confirm/?email={}&conf_num={}'> Kliknij w poniższy link</a>.<h2>".format(request.build_absolute_uri(host), sub.email, sub.conf_num)) sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY')) response = sg.send(message) return render(request, 'newsletter/newsletter.html', {'email': sub.email, 'action': 'wysłano', 'form': NewsletterUserForm()}) else: # 校验不通过,把带错误信息的表单传回模板 return render(request, 'newsletter/newsletter.html', {'form': form}) else: return render(request, 'newsletter/newsletter.html', {'form': NewsletterUserForm()})
2. (可选)自定义邮箱重复的错误提示
在forms.py中修改字段定义,添加自定义错误信息,展示更友好:
class NewsletterUserForm (forms.ModelForm): email = forms.EmailField( label='Twój email', max_length=100, widget=forms.EmailInput(attrs={'class': 'form-control'}), # 自定义错误提示 error_messages={'unique': '该邮箱已经订阅过我们的通讯了'} ) class Meta: model = NewsletterUser fields = ['email']
3. 模板无需修改
你已经使用了crispy_forms渲染表单,表单校验失败后会自动在输入框下方展示错误提示,不会再抛出数据库异常。
可选优化
如果需要支持用户重复提交未验证的邮箱时重发验证邮件,可以在校验到邮箱已存在时,判断对应的confirmed字段状态,如果是未验证,就更新验证码重新发邮件,无需提示重复。
内容的提问来源于stack exchange,提问作者Tomasz
相关产品推荐
相关产品推荐

