Je souhaite demander au code suivant de mettre à jour le mot de passe, mais je souhaite le mettre à jour après le processus de confirmation du mot de passe actuel. Alors, que dois-je ajouter pour cela? Je vous remercie.
class UserPasswordSerializer(ModelSerializer):
class Meta:
model = User
fields = [
'password'
]
extra_kwargs = {
"password": {"write_only": True},
}
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if attr == 'password':
instance.set_password(value)
else:
setattr(instance, attr, value)
instance.save()
return instance
Je crois que l'utilisation d'un modeler sérialisant pourrait être un excès Ce sérialiseur simple et cette vue devraient fonctionner.
Serializers.py
from rest_framework import serializers
class ChangePasswordSerializer(serializers.Serializer):
"""
Serializer for password change endpoint.
"""
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
Views.py
from rest_framework import status
from rest_framework import generics
from rest_framework.response import Response
from Django.contrib.auth.models import User
from . import serializers
from rest_framework.permissions import IsAuthenticated
class ChangePasswordView(UpdateAPIView):
"""
An endpoint for changing password.
"""
serializer_class = ChangePasswordSerializer
model = User
permission_classes = (IsAuthenticated,)
def get_object(self, queryset=None):
obj = self.request.user
return obj
def update(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
# Check old password
if not self.object.check_password(serializer.data.get("old_password")):
return Response({"old_password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST)
# set_password also hashes the password that the user will get
self.object.set_password(serializer.data.get("new_password"))
self.object.save()
return Response("Success.", status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@ Yiğit Güler a donné une bonne réponse, merci, mais cela pourrait être mieux en quelques points mineurs.
Tant que vous ne travaillez pas vraiment avec UpdateModelMixin , mais directement avec l'instance d'utilisateur de la requête, vous n'avez pas besoin d'utiliser un UpdateAPIView . Un simple APIView suffit.
En outre, lorsque le mot de passe est modifié, vous pouvez renvoyer un status.HTTP_204_NO_CONTENT
au lieu d'un 200 avec du contenu aléatoire.
Au fait, n’oubliez pas de valider votre nouveau mot de passe avant de l’enregistrer. C'est dommage si vous autorisez le "mot de passe" lors de la mise à jour alors que vous ne le créez pas.
J'utilise donc le code suivant dans mon projet:
from Django.contrib.auth.password_validation import validate_password
class ChangePasswordSerializer(serializers.Serializer):
"""
Serializer for password change endpoint.
"""
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
def validate_new_password(self, value):
validate_password(value)
return value
Et pour la vue:
class UpdatePassword(APIView):
"""
An endpoint for changing password.
"""
permission_classes = (permissions.IsAuthenticated, )
def get_object(self, queryset=None):
return self.request.user
def put(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = ChangePasswordSerializer(data=request.data)
if serializer.is_valid():
# Check old password
old_password = serializer.data.get("old_password")
if not self.object.check_password(old_password):
return Response({"old_password": ["Wrong password."]},
status=status.HTTP_400_BAD_REQUEST)
# set_password also hashes the password that the user will get
self.object.set_password(serializer.data.get("new_password"))
self.object.save()
return Response(status=status.HTTP_204_NO_CONTENT)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Après avoir enregistré l'utilisateur, vous voudrez peut-être vous assurer qu'il reste connecté (après Django = 1.7, un utilisateur est automatiquement déconnecté lors du changement de mot de passe):
from Django.contrib.auth import update_session_auth_hash
# make sure the user stays logged in
update_session_auth_hash(request, self.object)
Je pense que la solution la plus facile (quand je dis plus facile, je veux dire la plus courte possible et la plus propre) serait quelque chose comme:
Voir la classe
class APIChangePasswordView(UpdateAPIView):
serializer_class = UserPasswordChangeSerializer
model = get_user_model() # your user model
permission_classes = (IsAuthenticated,)
def get_object(self, queryset=None):
return self.request.user
Classe de sérialiseur
from rest_framework import serializers
from rest_framework.serializers import Serializer
class UserPasswordChangeSerializer(Serializer):
old_password = serializers.CharField(required=True, max_length=30)
password = serializers.CharField(required=True, max_length=30)
confirmed_password = serializers.CharField(required=True, max_length=30)
def validate(self, data):
# add here additional check for password strength if needed
if not self.context['request'].user.check_password(data.get('old_password')):
raise serializers.ValidationError({'old_password': 'Wrong password.'})
if data.get('confirmed_password') != data.get('password'):
raise serializers.ValidationError({'password': 'Password must be confirmed correctly.'})
return data
def update(self, instance, validated_data):
instance.set_password(validated_data['password'])
instance.save()
return instance
def create(self, validated_data):
pass
@property
def data(self):
# just return success dictionary. you can change this to your need, but i dont think output should be user data after password change
return {'Success': True}
serializer.py
class UserSer(serializers.ModelSerializers):
class meta:
model=UserModel
fields = '__all__'
views.py
class UserView(UpdateAPIView):
serializer_class = serializers.UserSer
queryset = models.User.objects.all()
def get_object(self,pk):
try:
return models.User.objects.get(pk=pk)
except Exception as e:
return Response({'message':str(e)})
def put(self,request,pk,format=None):
user = self.get_object(pk)
serializer = self.serializer_class(user,data=request.data)
if serializer.is_valid():
serializer.save()
user.set_password(serializer.data.get('password'))
user.save()
return Response(serializer.data)
return Response({'message':True})