You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试Django PasswordChangeForm?表单验证通过但视图提交报错

问题:PasswordChangeForm测试中表单验证通过但POST请求失败

我正尝试为使用PasswordChangeForm的密码修改视图编写测试,测试代码如下:

def test_profile_change_password(self):
    self.client.force_login(self.user)
    self.user.set_password(self.password)
    new_password = random_password()
    payload = {
        "old_password": self.password,
        "new_password1": new_password,
        "new_password2": new_password,
    }
    form = PasswordChangeForm(user=self.user, data=payload)
    self.assertTrue(form.is_valid())
    
    response = self.client.get(
        reverse_lazy("researcher_ui:change_password"),
    )
    self.assertEqual(response.template_name, ["researcher_UI/change_password.html"])

    response = self.client.post(
        reverse_lazy("researcher_ui:change_password"), payload
    )
    print(response.context['form'].error_messages)

单独验证表单时self.assertTrue(form.is_valid())测试通过,但使用client.post提交相同数据到视图时,却收到错误信息:{'password_mismatch': 'The two password fields didn’t match.', 'password_incorrect': 'Your old password was entered incorrectly. Please enter it again.'}。按逻辑表单验证通过就不应出现这类错误,请问我哪里操作有误?


分析与解决方法

1. 核心问题:修改密码后未保存用户实例

你调用self.user.set_password(self.password)仅在内存中修改了用户的密码哈希值,但没有将该变更保存到数据库。单独验证表单时,使用的是内存中的用户对象,验证能正常通过;但client.post请求视图时,视图会从数据库读取用户数据,此时数据库里的用户密码仍是初始值,因此触发「旧密码错误」的验证失败。

修正方式:在set_password后添加保存操作:

self.user.set_password(self.password)
self.user.save()  # 新增该行,将密码变更同步到数据库

2. 次要问题:表单字段名可能不匹配

错误中的「两次密码不匹配」提示,大概率是模板里的表单字段name属性与PasswordChangeForm要求的不一致。PasswordChangeForm规定的新密码字段为new_password1和new_password2,若模板中写成new_password等其他名称,POST提交的数据无法匹配表单字段,就会出现该错误。

检查模板:确保字段name与payload键一致:

<form method="post">
    {% csrf_token %}
    <!-- 推荐使用form.as_p自动渲染,避免手动写错字段名 -->
    {{ form.as_p }}
    <!-- 手动渲染时需保证name正确 -->
    <!-- <input type="password" name="old_password" required> -->
    <!-- <input type="password" name="new_password1" required> -->
    <!-- <input type="password" name="new_password2" required> -->
    <button type="submit">修改密码</button>
</form>

修正后的完整测试代码

def test_profile_change_password(self):
    self.client.force_login(self.user)
    # 修改密码后必须保存到数据库
    self.user.set_password(self.password)
    self.user.save()
    new_password = random_password()
    payload = {
        "old_password": self.password,
        "new_password1": new_password,
        "new_password2": new_password,
    }
    form = PasswordChangeForm(user=self.user, data=payload)
    self.assertTrue(form.is_valid())
    
    response = self.client.get(
        reverse_lazy("researcher_ui:change_password"),
    )
    self.assertEqual(response.template_name, ["researcher_UI/change_password.html"])

    response = self.client.post(
        reverse_lazy("researcher_ui:change_password"), payload
    )
    # 验证密码修改成功后的重定向(通常为302状态码)
    self.assertEqual(response.status_code, 302)
    # 刷新用户实例并验证密码确实被修改
    self.user.refresh_from_db()
    self.assertTrue(self.user.check_password(new_password))

内容的提问来源于stack exchange,提问作者HenryM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:57:34