Django更新用户资料提交原邮箱提示已存在的解决方法
根本原因
你的Account模型中email字段设置了unique=True唯一性约束,你在实例化UserProfileUpdateForm时没有传入instance参数指定要更新的现有用户对象,Django ModelForm会默认按照「创建新用户」的逻辑做全局唯一性校验,哪怕提交的是当前用户正在使用的邮箱,也会判定为重复。
同时你当前的表单初始化代码中额外弹出了user参数,但实际没有使用,也可以同步优化,避免传参冗余。
解决方案
1. 修改视图层代码
实例化表单时必须传入instance参数,指定需要更新的当前用户实例,GET/POST请求都需要传入,GET请求传入后还可以自动填充表单原有数据:
@login_required def user_profile(request, id): if request.user.id == int(id): # 直接复用request.user无需重复查询数据库 user = request.user if request.method == "POST": # 传入instance参数,告知表单是更新现有对象而非新建 form = UserProfileUpdateForm(request.POST, instance=user) if form.is_valid(): form.save() messages.success(request, mark_safe("UPDATE: <br> your profile is updated")) context = {"form": form} return render(request, "accounts/user_profile.html", context) else: # 保留原有错误处理逻辑 pass else: # GET请求传入instance自动填充表单原有值 form = UserProfileUpdateForm(instance=user) context = {"form": form} return render(request, "accounts/user_profile.html", context) else: return redirect("not_found")
2. 修改表单层代码
删除冗余的user参数接收逻辑,需要使用当前用户对象时直接调用self.instance即可,同时注意删除fields中重复声明的year、month、day避免表单字段冲突:
class UserProfileUpdateForm(forms.ModelForm): class Meta: model = Account fields = ["first_name", "last_name", "first_name_kana", "last_name_kana", "post_code", "city", "address", "building", "tel", "sex", "occupation", "year", "month", "day", "parent_name", "parent_name_kana", "school_type", "school_name", "student_id", "email"] def __init__(self, *args, **kwargs): now = datetime.datetime.now() # 删除原有pop user的冗余代码 super(UserProfileUpdateForm, self).__init__(*args, **kwargs) # 需要使用当前用户直接取self.instance即可 # 保留原有widget设置逻辑
可选:自定义邮箱校验(非必须)
如果有自定义校验需求,你也可以新增clean_email方法手动控制校验逻辑:
def clean_email(self): email = self.cleaned_data.get("email") # 排除当前用户自身后查询是否存在重复邮箱 if Account.objects.filter(email=email).exclude(pk=self.instance.pk).exists(): raise forms.ValidationError("该邮箱已被其他账号注册使用") return email
修改完成后提交原邮箱就不会再触发重复报错,正常完成资料更新。
内容的提问来源于stack exchange,提问作者yvl
相关产品推荐
相关产品推荐

