Reputation: 252
I'm trying to write a serializer (in Django REST Framework) to update a user's account details. Here is the update() method:
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)
When I perform a PATCH request to the view with "password", "confirm_password" and "old_password" as fields, it appears to have worked. Then when I try to log into the account again, it fails (using both old and new passwords). When I check the admin settings and view the user I am trying to edit, I get the following:
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.
I believe User.set_password() is supposed to handle hashing/etc. automatically, so why do I get this error?
Upvotes: 1
Views: 580
Reputation: 252
In case anyone is interested in using my code, here is the final working code:
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)
Upvotes: 1
Reputation: 47354
You deleted password
from self.validated_data
but not from validated_data
dict which passed to superclass's update
method. Try this:
validated_data.pop("password") # remove self, just leave validated_data
return super(UserInfoSerializer, self).update(instance, validated_data)
Upvotes: 2