Django更新用户密码调用set_password()后仍存明文的问题求解
问题原因
你在调用set_password()完成密码加密并保存用户后,又将携带明文密码的request.data传入序列化器执行了第二次保存操作,序列化器默认会直接用请求中的明文密码覆盖已经加密好的密码字段,导致最终存储的是明文。
修复方案
方案1:调整视图逻辑执行顺序
取消冗余的两次保存,先通过序列化器完成参数校验,再处理密码加密逻辑,示例代码如下:
def put(self, request, pk, format=None): user = self.get_user(pk) # 先执行参数校验,partial参数可选,用于支持部分字段更新 serializers = UserSerializer(user, data=request.data, partial=True) if serializers.is_valid(): # 校验通过后处理密码加密 new_password = serializers.validated_data.get("password") user = serializers.save() if new_password: user.set_password(new_password) user.save() return Response(serializers.data) else: return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
方案2(更规范):将加密逻辑封装到序列化器中
在UserSerializer中重写update方法,统一处理密码加密逻辑,避免视图层重复处理:
# 序列化器新增update方法逻辑 def update(self, instance, validated_data): # 取出密码不参与默认更新逻辑 password = validated_data.pop('password', None) instance = super().update(instance, validated_data) # 如果请求携带新密码,加密后保存 if password: instance.set_password(password) instance.save() return instance
调整后视图层不需要单独处理密码,直接调用序列化器保存即可:
def put(self, request, pk, format=None): user = self.get_user(pk) serializers = UserSerializer(user, data=request.data, partial=True) if serializers.is_valid(): serializers.save() return Response(serializers.data) return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)
补充注意
建议在序列化器中将password字段设置为write_only=True,避免接口返回响应时泄露密码字段内容。
内容的提问来源于stack exchange,提问作者siderra
相关产品推荐
相关产品推荐

