Django User.set_password 导致密码无效

Django User.set_password leads to invalid password

我正在尝试编写一个序列化程序(在 Django REST Framework 中)来更新用户的帐户详细信息。这是 update() 方法:

def update(self, instance, validated_data):
    ...
    if all([item in self.validated_data for item in ["password", "confirm_password", "old_password"]]):
        user = authenticate(username=self.context["request"].user.username, password=self.validated_data["old_password"])
        if user is not None:
            if self.validated_data["password"] == self.validated_data["confirm_password"]:
                validate_password(self.validated_data["password"])
                user.set_password(self.validated_data["password"])
                user.save()
            else:
                raise serializers.ValidationError({"confirm_password": "Passwords do not match"})
        else:
            raise serializers.ValidationError({"old_password": "Password incorrect"})

    self.validated_data.pop("password")

    return super(UserInfoSerializer, self).update(instance, validated_data)

当我对以 "password"、"confirm_password" 和 "old_password" 作为字段的视图执行 PATCH 请求时,它似乎有效。然后,当我再次尝试登录该帐户时,它失败了(同时使用旧密码和新密码)。当我检查管理员设置并查看我正在尝试编辑的用户时,我得到以下信息:

Invalid password format or unknown hashing algorithm.

Raw passwords are not stored, so there is no way to see this user's password, but you can change the password using this form.

我相信 User.set_password() 应该处理 hashing/etc。自动,为什么我会收到此错误?

您从 self.validated_data 中删除了 password,但没有从传递给超类的 update 方法的 validated_data 字典中删除。试试这个:

validated_data.pop("password") # remove self, just leave validated_data

return super(UserInfoSerializer, self).update(instance, validated_data)

如果有人有兴趣使用我的代码,这里是最终的工作代码:

def update(self, instance, validated_data):
    ...
    if all([item in validated_data for item in ["password", "confirm_password", "old_password"]]):
        user = authenticate(username=instance.username, password=validated_data["old_password"])
        if user is not None and user == instance:
            if validated_data["password"] == validated_data["confirm_password"]:
                validate_password(validated_data["password"])
                instance.set_password(validated_data["password"])
                instance.save()  # change the password on the current instance object, otherwise changes will be overwritten
                login(self.context["request"], instance)  # without this line, the user is auto-logged out upon changing their password
            else:
                raise serializers.ValidationError({"confirm_password": "Passwords do not match"})
        else:
            raise serializers.ValidationError({"old_password": "Password incorrect"})

    if "password" in validated_data:
        validated_data.pop("password")

    return super(UserInfoSerializer, self).update(instance, validated_data)