I'm new to django rest framework. I'm implementing a simple login, signup and forgot password functionality using reactJs and django. All the functionalities are working fine but the problem I'm facing is that, on signup, the passwords in the database encrypted and then saved in the database but on updating password, the new password saved exactly same as user typed it. I want it also be encrypted in the database just like it encrypted in signup.
My serializer.py file
from dataclasses import fields
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields='__all__'
# fields = ('username','first_name', 'last_name', 'email')
class UserSerializerWithToken(serializers.ModelSerializer):
token = serializers.SerializerMethodField()
password = serializers.CharField(write_only=True)
def get_token(self, obj):
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(obj)
token = jwt_encode_handler(payload)
return token
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class Meta:
model = User
fields = ('token','first_name', 'last_name','email', 'username', 'password')
My views.py file
from asyncio.windows_events import NULL
from django.http import Http404, HttpResponseRedirect
from django.contrib.auth.models import User
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserSerializer
from .serializers import UserSerializerWithToken
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
@api_view(['GET'])
def current_user(request):
"""
Determine the current user by their token, and return their data
"""
serializer = UserSerializer(request.user)
return Response(serializer.data)
@api_view(['GET'])
def get_user(request):
"""
Filter the user wrt username and return the user data and token
"""
user=User.objects.filter(email=request.query_params['email'])
serializer = UserSerializer(instance=user, many=True)
if user.exists():
return Response(serializer.data)
else:
return Response(serializer.errors)
# ########################################################
# This is my update user api to update password
# it updates the password but not encrypting the password
# like signup encrypts in database
# ########################################################
@api_view(['PUT'])
def update_user(request,id):
user=User.objects.get(pk=id)
# userdata={'id':user.id,'username':user.username,'first_name':user.first_name,'last_name':user.last_name,'password':user.password}
serializer=UserSerializer(instance=user, data=request.data[0])
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class UserList(APIView):
"""
Create a new user. It's called 'UserList' because normally we'd have a get
method here too, for retrieving a list of all User objects.
"""
# permission_classes = (permissions.AllowAny,)
def post(self, request, format=None):
serializer = UserSerializerWithToken(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# ############################################################################
# I tried the following way as well but it doesn't even update the password
# ############################################################################
#
# def put(self,request,id,format=None):
# user=User.objects.get(pk=id)
# serializer=UserSerializerWithToken(instance=user, data=request.data)
# if serializer.is_valid():
# serializer.save()
# return Response(serializer.data)
# else:
# return Response(serializer.errors)
This is the url I'm using for api
path('users/<int:id>/',UserList.as_view()),
And this is how I called this api from reactjs
function handleSubmit(e) {
let user=JSON.parse(localStorage.getItem('matched_user_token'))[0]
user.password=new_password
e.preventDefault()
if (ValidatePassword()) {
fetch('http://localhost:8000/core/users/' user.id '/', {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
.then(res => res.json())
.then(json => {
console.log("password changed successfully!" json)
localStorage.setItem('changed',true)
navigate('/login')
}).catch(errors=>console.log(errors))
}
}
CodePudding user response:
You need to override serializer's update
method like this:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields='__all__'
def update(self, instance, validated_data):
if 'password' in validated_data:
password = validated_data.pop('password', None)
instance.set_password(password)
return super().update(instance, validated_data)