You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am trying to confirm the password reset (with retype) at the /users/reset_password_confirm/ endpoint. The error I am getting is:
Traceback (most recent call last):
# ...
File "/home/django/venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/home/django/venv/lib/python3.10/site-packages/djoser/views.py", line 248, in reset_password_confirm
serializer.is_valid(raise_exception=True)
File "/home/django/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 227, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "/home/django/venv/lib/python3.10/site-packages/rest_framework/serializers.py", line 429, in run_validation
value = self.validate(value)
File "/home/django/venv/lib/python3.10/site-packages/djoser/serializers.py", line 169, in validate
validated_data = super().validate(attrs)
File "/home/django/venv/lib/python3.10/site-packages/djoser/serializers.py", line 229, in validate
attrs = super().validate(attrs)
File "/home/django/venv/lib/python3.10/site-packages/djoser/serializers.py", line 210, in validate
user = self.context["request"].user or self.user
AttributeError: 'PasswordResetConfirmRetypeSerializer' object has no attribute 'user'
I investigated on the resolution order of validate methods called when starting with PasswordResetConfirmRetypeSerializer and apparently it's something like this:
The problem appears in PasswordSerializer (D) where the user is not yet attached to our serializer instance, because current UidAndTokenSerializer (B) runs its two validate steps in a wrong order (see red text in the image above). As a fix for this I decided to change the order of these two steps (see green text in the image below):
This is the override code I prepared: settings.py:
fromdjango.contrib.authimportget_user_modelfromdjoserimportutilsfromdjoser.confimportsettingsfromdjoser.serializersimport (
UserCreatePasswordRetypeSerializer, PasswordRetypeSerializer,
)
fromrest_frameworkimportserializersfromrest_framework.exceptionsimportValidationErrorUser=get_user_model()
classUidAndTokenSerializerOverride(serializers.Serializer):
""" This class is a rough copy of UidAndTokenSerializer with an overridden validate method. We don't want to inherit from UidAndTokenSerializer, because there's no need to run its validate method with super().validate(attrs) once we perform the validation logic here. """uid=serializers.CharField()
token=serializers.CharField()
default_error_messages= {
"invalid_token": settings.CONSTANTS.messages.INVALID_TOKEN_ERROR,
"invalid_uid": settings.CONSTANTS.messages.INVALID_UID_ERROR,
}
def_assign_user_if_valid_uid_and_token(self, uid, token):
""" Assigns user to self if provided uid and token are valid. Otherwise, raises ValidationErrors. """try:
decoded_uid=utils.decode_uid(uid)
self.user=User.objects.get(pk=decoded_uid)
except (User.DoesNotExist, ValueError, TypeError, OverflowError):
key_error="invalid_uid"raiseValidationError(
{"uid": [self.error_messages[key_error]]}, code=key_error
)
is_token_valid=self.context["view"].token_generator.check_token(
self.user, token
)
ifnotis_token_valid:
key_error="invalid_token"raiseValidationError(
{"token": [self.error_messages[key_error]]}, code=key_error
)
defvalidate(self, attrs):
""" Overriding this method as original UidAndTokenSerializer first runs super().validate(attrs) and only then assigns user to the instance based on credentials. This results in an error, as super().validate(attrs) requires the user to be already authenticated. This override switches the order of these two steps. """self._assign_user_if_valid_uid_and_token(
self.initial_data.get("uid", ""), self.initial_data.get("token", "")
)
validated_data=super().validate(attrs)
returnvalidated_dataclassPasswordResetConfirmRetypeSerializerOverride(
UidAndTokenSerializerOverride,
PasswordRetypeSerializer,
):
pass
The app seems to be working properly now and the password is reset. Is there something wrong in how I'm using/understanding Djoser in this scenario or is it a bug?
The text was updated successfully, but these errors were encountered:
I am trying to confirm the password reset (with retype) at the
/users/reset_password_confirm/
endpoint. The error I am getting is:I investigated on the resolution order of
validate
methods called when starting withPasswordResetConfirmRetypeSerializer
and apparently it's something like this:The problem appears in
PasswordSerializer (D)
where the user is not yet attached to our serializer instance, because currentUidAndTokenSerializer (B)
runs its twovalidate
steps in a wrong order (see red text in the image above). As a fix for this I decided to change the order of these two steps (see green text in the image below):This is the override code I prepared:
settings.py
:my_app.users.serializers.py
:The app seems to be working properly now and the password is reset. Is there something wrong in how I'm using/understanding Djoser in this scenario or is it a bug?
The text was updated successfully, but these errors were encountered: