Django自定义用户更新资料时邮箱唯一校验逻辑异常问题解决
Django自定义用户更新表单邮箱校验异常解决方案
问题根因
- 视图实例化表单时没有将当前登录用户的数据库实例绑定到表单上。Django的ModelForm对带
unique=True约束的字段做校验时,如果绑定了编辑实例,会自动排除该实例本身的记录做重复检查;如果没有绑定实例,会把提交的内容当成新增数据校验,哪怕是用户自己原有的邮箱,也会被判定为重复。 - 之前写的空
clean()方法完全覆盖了Django内置的所有校验逻辑(包括唯一性校验、字段格式校验),等于关闭了所有服务端校验。此时如果提交其他用户已有的邮箱,表单不会拦截,直接走到数据库层触发唯一约束冲突,抛出500错误。
具体修改步骤
1. 恢复表单的默认校验逻辑
删掉CustomUserChangeForm里多余的空clean()方法,最终表单代码如下:
class CustomUserChangeForm(UserChangeForm): class Meta: model = CustomUser fields = ('email','first_name', 'last_name')
2. 修正视图的表单初始化逻辑
去掉冗余的手动查用户、手动填充初始值、手动赋值字段的逻辑,按照Django ModelForm的标准用法,在初始化表单时绑定当前用户实例,代码如下:
def update_user_view(request): # 直接取当前登录用户对象,无需重复查询数据库 current_user = request.user if request.method == 'POST': # 绑定当前用户实例做编辑,校验时会自动排除当前用户的邮箱记录 form = CustomUserChangeForm(request.POST, request.FILES, instance=current_user) if form.is_valid(): # 直接调用表单自带save方法更新数据,无需手动逐字段赋值 form.save() return redirect('accounts:update_user') else: # GET请求时绑定实例,表单会自动填充用户现有数据,无需手动写initial form = CustomUserChangeForm(instance=current_user) context = {'form': form} return render(request, 'accounts/update_user.html', context)
修改后效果
- 用户仅修改姓名、不更换邮箱提交时,不会再误触发“邮箱已存在”的报错
- 用户尝试将邮箱修改为其他用户已使用的邮箱时,会正常在表单上显示对应的校验错误,不会触发500页面
额外注意
你的managers.py里存在拼写错误:extra_feilds应为extra_fields,虽然当前不影响功能,建议尽早修正避免后续出bug。
内容的提问来源于stack exchange,提问作者Kieran Yardley
相关产品推荐
相关产品推荐

