为何Django表单提交出错仍更新实例?如何规避该问题?
解决Django表单验证失败时修改原用户实例的问题
当表单验证不通过(比如用户名重复)时,construct_instance会直接修改绑定的instance对象(也就是request.user),导致页面显示错误的用户名。可以通过以下两种方式解决:
方法一:使用用户实例的副本绑定表单
不要直接用request.user作为表单的instance参数,而是先创建一个用户对象副本,让表单操作副本而非原实例,这样request.user的数据不会被篡改:
@login_required() def personal(request): if request.method == 'POST': # 从数据库重新获取用户实例作为副本,避免修改原request.user user_copy = User.objects.get(pk=request.user.pk) user_form = UserForm(request.POST, instance=user_copy) if user_form.is_valid(): # 保存时会更新数据库中的原用户数据(主键一致) user = user_form.save() update_session_auth_hash(request, user) messages.success(request, '个人信息修改成功!') return redirect('profile') else: user_form = UserForm(instance=request.user) context = { 'form': user_form, } return render(request, 'personal.html', context)
如果不想额外查询数据库,也可以用Django模型的_state.copy()方法创建内存中的副本:
user_copy = request.user._state.copy() user_form = UserForm(request.POST, instance=user_copy)
方法二:验证失败后重置用户实例(不推荐)
如果一定要绑定原request.user,可以在验证失败后从数据库重新拉取用户数据覆盖被修改的实例:
@login_required() def personal(request): if request.method == 'POST': user_form = UserForm(request.POST, instance=request.user) if user_form.is_valid(): user = user_form.save() update_session_auth_hash(request, user) messages.success(request, '个人信息修改成功!') return redirect('profile') else: # 验证失败后重置request.user为数据库中的原始数据 request.user = User.objects.get(pk=request.user.pk) else: user_form = UserForm(instance=request.user) context = { 'form': user_form, } return render(request, 'personal.html', context)
这种方法会修改request.user对象,可能在请求的其他环节引发意外,因此优先推荐方法一。
核心逻辑是:让表单操作的是用户实例的副本,而非request.user本身,这样即使验证失败,原实例的初始数据也能保留,页面就能正常显示初始用户名。
内容的提问来源于stack exchange,提问作者Serge P.
相关产品推荐
相关产品推荐

