Django ValidationError пользовательского сериализатора Rest Framework не работает - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь настроить настраиваемый сериализатор входа в систему в Django и хочу настраиваемый ответ, но по умолчанию всегда отображается:

{
    "username":[
        "This field is required."
    ],
    "password":[
        "This field is required."
    ]
}

Я пытался настроить свой сериализатор следующим образом:

 class MyLoginSerializer(serializers.Serializer):
    username = serializers.CharField(required=True, allow_blank=True)
    email = serializers.EmailField(required=False, allow_blank=True)
    password = serializers.CharField(style={'input_type': 'password'})
    def authenticate(self, **kwargs):
        return authenticate(self.context['request'], **kwargs)
    def _validate_email(self, email, password):
        user = None
        if email and password:
            user = self.authenticate(email=email, password=password)
        else:
            msg = _('Must include "email" and "password".')
            raise serializers.ValidationError(msg)
        return user
    def _validate_username(self, username, password):
        print("in username")
        user = None
        if username and password:
            print("in username 2")
            try:
                user = self.authenticate(username=username, password=password)
            except Exception:
                raise serializers.ValidationError("Wrong")
        else:
            print("in username 3")
            msg = _('Must include "username" and "password".')
            raise serializers.ValidationError(msg)
        return user
    def _validate_username_email(self, username, email, password):
        user = None
        if email and password:
            user = self.authenticate(email=email, password=password)
        elif username and password:
            user = self.authenticate(username=username, password=password)
        else:
            msg = _(
                'Must include either "username" or "email" and "password".'
                )
            raise serializers.ValidationError(msg)
        return user
    def validate(self, attrs):
        username = attrs.get('username')
        email = attrs.get('email')
        password = attrs.get('password')
        user = None
        if 'allauth' in settings.INSTALLED_APPS:
            from allauth.account import app_settings
            # Authentication through email
            if (app_settings.AUTHENTICATION_METHOD ==
                    app_settings.AuthenticationMethod.EMAIL):
                user = self._validate_email(email, password)
            # Authentication through username
            elif (app_settings.AUTHENTICATION_METHOD ==
                    app_settings.AuthenticationMethod.USERNAME):
                user = self._validate_username(username, password)
            # Authentication through either username or email
            else:
                user = self._validate_username_email(username, email, password)
        else:
            # Authentication without using allauth
            if email:
                try:
                    username = GameUser.objects\
                        .get(email__iexact=email)\
                        .get_username()
                except UserModel.DoesNotExist:
                    pass
            if username:
                user = self._validate_username_email(username, '', password)
        # Did we get back an active user?
        if user:
            if not user.is_active:
                msg = ('User account is disabled.')
                raise exceptions.ValidationError(msg)
        else:
            msg = ('Wrong login information.')
            raise exceptions.ValidationError(msg)
        # If required, is the email verified?
        if 'rest_auth.registration' in settings.INSTALLED_APPS:
            from allauth.account import app_settings
            if app_settings.EMAIL_VERIFICATION == app_settings\
                    .EmailVerificationMethod\
                    .MANDATORY:
                email_address = user.emailaddress_set.get(email=user.email)
                if not email_address.verified:
                    raise serializers.ValidationError((
                        'E-mail is not verified.'
                    ))
        attrs['user'] = user
        return attrs

И у меня есть этот набор в качестве моего сериализатора входа в систему в моих settings.py:

REST_AUTH_SERIALIZERS ={
    'LOGIN_SERIALIZER': 'api.serializer.MyLoginSerializer'
}

А вот мой пользовательский вид входа в систему:

class CustomLoginView(LoginView):
    permission_classes = (AllowAny,)
    serializer_class = MyLoginSerializer
    def get_response(self):
        original_response = super().get_response()
        print("ORIGINAL REESPONSE:")
        print(str(self.user))
        mydata = {"username": str(self.user), "status": "success"}
        original_response.data.update(mydata)
        return original_response

Как бы Я получаю его, чтобы показать пользовательский 'Must include "email" and "password".' вместо сообщения по умолчанию?

Спасибо!

1 Ответ

0 голосов
/ 29 апреля 2020

Краткий ответ, используйте сериализатор для проверки данных, затем настройте ответы на основе валидатора сериализаторов. Вы могли бы даже go использовать варианты.

Базовая c структура для этого реализована в вашем представлении / наборе вида как:

class MyViewSet(viewsets.ModelViewSet):
    """
    My View Set
    """
    queryset = #
    serializer_class = #

    # take which ever method you want to add the custom formatting to
    # and modify it, or create a new method with its own special endpoint
    def view_set_method_to_modify(self, *other_args):

        # Do some stuff to keep the desired functions of the method you are hacking

        serializer = serializers.MySerializer(data=request.data, context={"request": request})
        if serializer.is_valid():

            # Do some stuff with serializer.validated_data['my_var'])

            return Response({'message': 'Yay the data is valid!!!'},
                status=status.HTTP_200_OK)
        return Response(serializer.errors,
            status=status.HTTP_400_BAD_REQUEST)

Вот пример, который Я работаю, чтобы обновить пароли пользователей. Вместо того чтобы взломать существующий метод, я добавил новый метод с его собственной специальной конечной точкой.

views.py

class UserViewSet(viewsets.ModelViewSet):
    """
    User View Set
    """
    queryset = User.objects.all()
    serializer_class = serializers.UserSerializer

    @action(methods=['post'], detail=True,
            url_path='change-password', url_name='change_password')
    def set_password(self, request, pk=None):
        user = self.get_object()
        serializer = serializers.PasswordSerializer(data=request.data, context={"request": request})
        if serializer.is_valid():
            user.set_password(serializer.validated_data['new_password'])
            user.save()
            return Response({'message': 'password set'},
                status=status.HTTP_200_OK)
        return Response(serializer.errors,
            status=status.HTTP_400_BAD_REQUEST)

serializers.py

class PasswordSerializer(Serializer):
    old_password = CharField(required=True)
    new_password = CharField(required=True)

    def validate(self, data):
        request = self.context['request']
        user = request.user
        new_password = request.data['new_password']
        old_password = request.data['old_password']
        validate_passwords(old=old_password, new=new_password, user=user)
        return data
...