Django DRF:使序列化器字段值等于另一个

时间:2018-03-07 14:59:49

标签: django django-rest-framework

我正在创建一个端点来重置密码,并创建了序列化程序,视图,我使用django.contrib.auth.forms来获取数据并向用户发送电子邮件。 表单需要输入两次新密码,但我想要的是,只需编写一次,并使new_password2的值等于new_password1。例如,我想在Swagger上更改密码,因为它是普通的CharField而不是PasswordField,所以输入两次是没有意义的。

这是serializers.py ResetPasswordConfirm类

class ResetPasswordConfirmSerializer(serializers.Serializer):

    new_password1 = serializers.CharField(max_length=128)
    new_password2 = serializers.CharField(max_length=128)
    uid = serializers.CharField()
    token = serializers.CharField()
    set_password_form_class = SetPasswordForm

def __init__(self, *args, **kwargs):
    super(ResetPasswordConfirmSerializer, self).__init__(*args, **kwargs)
    self.set_password_form = None

def validate(self, value, *args, **kwargs):
    try:
        uid = force_text(uid_decoder(value['uid']))
        user = User.objects.get(pk=uid)
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        raise ValidationError({
            'uid': ['Invalid value']
        })

    self.set_password_form = self.set_password_form_class(user=user, data=value)
    if not self.set_password_form.is_valid():
        raise serializers.ValidationError(self.set_password_form.errors)
    if not default_token_generator.check_token(user, value['token']):
        raise ValidationError({
            'token': ['Invalid value']
        })
    return value

def save(self, **kwargs):
    return self.set_password_form.save()

并且,API视图

class ResetPasswordConfirmAPIView(GenericAPIView):
    serializer_class = ResetPasswordConfirmSerializer
    permission_classes = (AllowAny,)

@method_decorator(csrf_protect)
def dispatch(self, *args, **kwargs):
    return super(ResetPasswordConfirmAPIView, self).dispatch(*args, **kwargs)

def post(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response({
        'detail': _("Password has been reset"),
    }, status=status.HTTP_200_OK)

我尝试了不同的方式来new_password2 == new_password1,但我收到错误。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您只能在序列化程序中保留new_password1并更新您在validate方法内发送的数据:

class ResetPasswordConfirmSerializer(serializers.Serializer):

    new_password1 = serializers.CharField(max_length=128)
    uid = serializers.CharField()
    token = serializers.CharField()
    set_password_form_class = SetPasswordForm

    def __init__(self, *args, **kwargs):
        super(ResetPasswordConfirmSerializer, self).__init__(*args, **kwargs)
        self.set_password_form = None

    def validate(self, value, *args, **kwargs):
        try:
            uid = force_text(uid_decoder(value['uid']))
            user = User.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            raise ValidationError({
                'uid': ['Invalid value']
            })

        new_value = value.copy()
        new_value['new_password2'] = value['new_password1'] 

        self.set_password_form = self.set_password_form_class(user=user, data=new_value)
        if not self.set_password_form.is_valid():
            raise serializers.ValidationError(self.set_password_form.errors)
        if not default_token_generator.check_token(user, value['token']):
            raise ValidationError({
                'token': ['Invalid value']
            })
        return value

    def save(self, **kwargs):
        return self.set_password_form.save()

但我认为没有形式也可以更清楚地做到这一点,你可以使用django的validate_password函数来验证密码。我没有测试它,但你可以尝试这样的事情:

from django.contrib.auth.password_validation import validate_password

class ResetPasswordConfirmSerializer(serializers.Serializer):
    new_password1 = serializers.CharField(max_length=128)
    uid = serializers.CharField()
    token = serializers.CharField()

    def validate(self, value, *args, **kwargs):
        try:
            uid = force_text(uid_decoder(value['uid']))
            user = User.objects.get(pk=uid)
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            raise ValidationError({
                'uid': ['Invalid value']
            })

        if not default_token_generator.check_token(user, value['token']):
            raise ValidationError({
                'token': ['Invalid value']
            })
        validate_password(password=value['new_password1'], user=user) 
        return value

    def save(self, **kwargs):
        user = User.objects.get(pk=self.validated_data['uid'])  
        user.set_password(self.validated_data['new_password1'])
        user.save()
        return user