【问题标题】:Django rest change users password viewDjango rest 更改用户密码视图
【发布时间】:2014-06-10 03:37:12
【问题描述】:

我正在使用 Django Rest 创建一个简单的 API。我需要创建一个视图,用户可以在其中更改他/她的密码。我正在使用默认的 Django 用户模型和一个简单的UserSerializer。有一种名为set_password 的方法,但我找不到与用户seriliazer 正确使用它的方法。我在任何地方都找不到任何解决方案。

用户序列化器:

class UserSerializer(serializers.ModelSerializer):

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

View(ClassedBased):这是一个例子(我不知道我在这里做什么):

    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)

请注意,我想发布一个 json 脚本来更改密码。像这样的东西:

 {
    "old_password": "123", 
    "new_password": "12345"
}

【问题讨论】:

  • 你为什么要调用 set_password() 两次?
  • UserSerializer 中没有用于以编码形式制作密码。它与我想要的无关。我会带走它,因为有些人会感到困惑
  • 您必须将其作为单独的视图吗?我在ModelViewSet 中以另一种方式做到了,就像这样dpaste.com/0EBYX24

标签: python django rest django-rest-framework


【解决方案1】:

一种方法是覆盖序列化程序中的 restore_object 方法。这看起来像这样:

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)

现在,当它反序列化为对象实例时,您将拥有一个有效的散列密码。然后,您应该能够通过稍微修改您当前拥有的视图来完成您想要的。

   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)

而且我相信您的 PATCH 请求中的 JSON(取决于查找类型,我认为默认为 id)看起来像这样:

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

我希望这会有所帮助!


编辑:

请注意,正如 Symmetric 在 cmets 中指出的那样,restore_object 在 DRF 3.0 中已被弃用

【讨论】:

【解决方案2】:

使用 Viewset 重置密码

在视图中

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)

您可以在 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')

【讨论】:

    【解决方案3】:

    您的问题已在以下地址得到解答:https://stackoverflow.com/a/27586192/2950621

    不要对视图类中的密码做任何事情。在 UserSerializer 类的重写 createupdate 方法中添加 set_password 调用。

    您的patch(部分更新)视图可以使用ModelViewSet 创建,例如:

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

    根据引用答案中的@DRC,在UserSerializer 类上添加createupdate 方法:

       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
    

    此外,您传入的 JSON 应该看起来更像:

    {
        "username": "mariodev", 
        "password": "12345"
    }
    

    【讨论】:

      猜你喜欢
      • 2022-10-07
      • 1970-01-01
      • 2018-09-22
      • 1970-01-01
      • 1970-01-01
      • 2016-12-15
      • 2015-08-29
      • 2012-04-26
      • 1970-01-01
      相关资源
      最近更新 更多