Django修改密码后发送邮件失效问题排查及验证逻辑疑问
修改密码功能失效问题排查及解答
问题背景
实现了继承自PasswordChangeView的修改密码视图,代码如下:
class ChangePasswordView(PasswordChangeView): form_class = ChangePasswordForm success_url = reverse_lazy('password_success') # success view def password_success(request): return render(request, 'accounts/password_success.html')
为添加密码修改后的邮件通知,在视图中重写了form_valid方法:
def form_valid(self, form): form.update_password_email() return redirect(self.success_url)
同时在ChangePasswordForm中新增邮件发送方法:
def update_password_email(self): email = self.cleaned_data.get('email', None) if email and self.is_valid(): send_mail( 'Password changed', 'Message', NOTIFICATION_EMAIL, [self.cleaned_data['email']], fail_silently=True )
实际测试时,输入旧密码、新密码及确认密码后,密码未修改且无邮件通知,直接跳转到success_url,需排查问题并解答form_valid()和if self.is_valid()是否重复的疑问。
问题排查与解决
1. 核心问题:视图重写form_valid跳过了父类的密码修改逻辑
PasswordChangeView的父类逻辑中,form_valid方法会调用form.save()完成密码修改操作。你重写该方法后,仅调用邮件发送并跳转,完全未执行父类的密码保存逻辑,这是密码未修改的根本原因。
正确实现方式:先执行父类的密码修改逻辑,再发送邮件:
def form_valid(self, form): # 先让父类完成密码修改 response = super().form_valid(form) # 再发送邮件通知 form.update_password_email() return response
或者手动调用表单的save方法:
def form_valid(self, form): form.save() # 手动执行密码修改保存 form.update_password_email() return redirect(self.success_url)
2. 表单邮件方法的两个错误
- 邮箱获取错误:
PasswordChangeForm默认仅包含旧密码、新密码、确认新密码字段,不包含email,所以self.cleaned_data.get('email')会返回None,导致邮件发送条件不满足。应从表单关联的用户实例获取邮箱:def update_password_email(self): email = self.user.email # PasswordChangeForm初始化时会传入user参数 send_mail( 'Password changed', 'Message', NOTIFICATION_EMAIL, [email], fail_silently=True ) - 冗余的验证判断:
form_valid仅在表单验证通过后才会被调用,此时self.is_valid()必然为True,表单方法中的if self.is_valid()完全多余,直接删除即可。
3. 关于form_valid()和self.is_valid()的重复问题
二者属于重复判断,不需要同时保留:
form_valid是视图层面的方法,触发前提就是表单已经通过is_valid()验证,所以在form_valid内部或其调用的表单方法中,再次执行self.is_valid()完全没有必要,还可能引发重复验证的额外开销。
内容的提问来源于stack exchange,提问作者Yehuda
相关产品推荐
相关产品推荐

