Django rest change user password

I am using Django Rest to create a simple API. I need to create a view in which the user can change their password. I am using the default Django user model and a simple UserSerializer . There is a method called set_password , but I can’t find a way to use it with user seriliazer.I can’t find any solution anywhere.

UserSelializer:

 class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', "username", 'email', 'first_name', 'last_name', 'password') 

View (ClassedBased): Here is an example (I have no idea what I'm doing here):

  class UserChangePassword(APIView): def patch(self, request): user = self.request.user serialized = UserSerializer(data=request.DATA) if serialized.is_valid(): user.set_password(serialized.data['password']) user.save() return Response(status=status.HTTP_205_RESET_CONTENT) else: return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST) 

Remember that I want to publish a json script to change the password. Something like that:

  { "old_password": "123", "new_password": "12345" } 
+7
python rest django django-rest-framework
source share
3 answers

One method may be to override the restore_object method in the Serializer. It will look something like this:

 class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', "username", 'email', 'first_name', 'last_name', 'password') # turn text to hashed password def restore_object(self, attrs, instance=None): attrs['password'] = make_password(attrs['password']) return super(UserSerializer, self).restore_object(attrs, instance=None) 

Now that this is deserialized into an instance of the object, you will have a valid hashed password. Then you can accomplish what you want by changing the view that you currently have a little.

  class UserChangePassword(APIView): def patch(self, request): serialized = UserSerializer(data=request.DATA) if serialized.is_valid(): serialized.save() return Response(status=status.HTTP_205_RESET_CONTENT) else: return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST) 

And I believe that the JSON in your PATCH request (depending on the type of search, which in my opinion is id by default) looks something like this:

 { "id": "83", "password": "12345" } 

Hope this helps!


EDIT:

Note that, as Symmetric points out in the comments, restore_object deprecated in DRF 3.0

+1
source share

Answered your question: stack overflow

Do not do anything about passwords in the presentation class. Add set_password calls to the overridden create and update methods in the UserSerializer class.

Your patch view (partial update) can be created using ModelViewSet , for example:

 class UserViewSet(viewsets.ModelViewSet): lookup_field = 'username' queryset = User.objects.all() serializer_class = serializers.UserSerializer 

According to @DRC in the above answer, add the create and update methods to the UserSerializer class:

  def create(self, validated_data): user = get_user_model(**validated_data) user.set_password(validated_data['password']) user.save() return user def update(self, instance, validated_data): for f in UserSerializer.Meta.fields + UserSerializer.Meta.write_only_fields: set_attr(instance, f, validated_data[f]) instance.set_password(validated_data['password']) instance.save() return instance 

In addition, your inbound JSON should look larger:

 { "username": "mariodev", "password": "12345" } 
0
source share

Password reset using Viewset

In view

 from rest_framework.decorators import detail_route, list_route, permission_classes from rest_framework import viewsets class UserProfileViewSet(viewsets.ViewSet): permission_classes = (AllowAny,) serializer_class = UserProfileSerializer def list(self, request): queryset = UserProfile.objects.all() serializer = self.serializer_class(queryset, many=True) return Response(serializer.data) def create(self, request): serializer = self.serializer_class(data=request.data) # check email address is exists or not. user_type = request.data['user_type'] user_token = register_by_social(request.data['email'], request.data['username'], user_type) if not user_token or user_token == True: if not User.objects.filter(Q(email=request.data['email']) | Q(username=request.data['username'])).exists(): if serializer.is_valid(): userprofile = serializer.save() return Response({ 'status': status.HTTP_201_CREATED, 'message': 'Successfully signup new user.', 'token': userprofile.user.auth_token.key }) return Response({ 'status': status.HTTP_400_BAD_REQUEST, 'message': 'Please provided required fields.', 'error' : serializer.errors }) return Response({ 'status': status.HTTP_409_CONFLICT, 'message': 'Email address or username is already exists.'}) return Response({ 'status': status.HTTP_200_OK, 'message': 'Social user is already registered.', 'token': user_token }) @list_route(permission_classes=[IsAuthenticated], authentication_classes = (BasicAuthentication, TokenAuthentication), methods=['post'], url_path='reset-user-password') def reset_user_password(self, request, pk=None): reset_password_serializer = UserResetPasswordSerializer(request.user, data=request.data) if reset_password_serializer.is_valid(): if not request.user.check_password(request.data.get('password')): return Response({"password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST) request.user.set_password(request.data.get('new_password')) request.user.save() return Response({"Message": ["Password reset successfully"]}, status=status.HTTP_200_OK) 

You can make serializer only for password in serializer.py

 import django.contrib.auth.password_validation as validators class UserResetPasswordSerializer(serializers.ModelSerializer): password = serializers.CharField(source='user.password', style={'input_type': 'password'}, max_length=20, min_length=8) new_password = serializers.CharField(style={'input_type': 'password'}, max_length=20, min_length=8) class Meta: model = User fields =("password", 'new_password') 
0
source share

All Articles