I am working on my Django (DRF) application. A have a CustomUser
model
class CustomAccountManager(BaseUserManager):
def create_superuser(self, email, user_name, password, **other_fields):
...
def create_user(self, email, user_name, password, **other_fields):
if not email:
raise ValueError(_('You must provide an email address'))
email = self.normalize_email(email)
user = self.model(email=email, user_name=user_name, **other_fields)
user.set_password(password)
user.save()
return user
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
user_name = models.CharField(max_length=150, unique=True) # Full name
phone_number = models.CharField(max_length=20, unique=True)
...
I have created a custom way to change password. I am sending current_password, new_password_verify and new_password_verify in body parameter.
My solution is working, but looks bulky What is the proper way to implement password change in Django?
class CustomUserViewSet(viewsets.ModelViewSet):
def update(self, request: Request, *args, **kwargs):
instance: CustomUser = self.get_object()
serializer = self.get_serializer(
instance, data=request.data, partial=True
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, "_prefetched_objects_cache", None):
instance._prefetched_objects_cache = {}
return Response({
"is_password_updated": self.update_password(request, instance), # <-------UPDATE
"result": serializer.data
})
def update_password(self, request, instance):
"""update password if 'new_password_verify' and 'new_password' are in request"""
if "current_password" in request.data and instance.check_password(request.data["current_password"]) and \
"new_password" in request.data and "new_password_verify" in request.data and \
request.data["new_password"] == request.data["new_password_verify"]:
instance.set_password(request.data["new_password"])
instance.save()
return True
return False
CodePudding user response:
I think you can extract the validating logic from the view to make it more modularized by defining the serializer.
class ChangePasswordSerializer(serializers.Serializer):
current_password = serializers.CharField(trim_whitespace = False, validators=[validate_password]),
new_password = serializers.CharField(trim_whitespace = False, validators=[validate_password])
new_password_verify = serializers.CharField(trim_whitespace = False)
def validate(self, attrs):
if attrs.get('new_password') != attrs.get('new_password_verify'):
serializers.ValidationError('Password and confirm password do not match')
return attrs
def validate_password(value):
# you can set your own validating logic here if you want to
# for example, like validations for length or regex
pass
Of course, you don't need to upload new_password_verify
data, and check that part in the frontend then the new_password_verify
field and validate
method is not necessary and the code will be simpler.
class CustomUserViewSet(viewsets.ModelViewSet):
def update(self, request: Request, *args, **kwargs):
...
return Response({
"is_password_updated": self.update_password(request, instance)
"result": serializer.data
})
def update_password(self, request, instance):
serializer = ChangePasswordSerializer(data = request.data)
if serializer.is_valid():
input_data = serializer.validated_data
cur_password = input_data.get('current_password')
new_password = input_data.get('new_password')
if instance.check_password(cur_password):
instance.set_password(new_password)
instance.save()
return True
return False