Django Rest Framework выбрасывает 400, прежде чем я могу обработать исключение для ModelViewSet

У меня есть модель пользователя в моем приложении с уникальным полем для email. Однако мне нужно отловить, когда пользователь пытается сделать дублирующий запрос, чтобы я мог выполнить некоторую обработку другим способом.

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

Но даже когда я создаю метод validate_email в своей модели или пытаюсь поймать его с помощью пользовательского исключения, он не ловится.

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

Как я могу поймать эту специфическую валидацию в Django Rest Framework?

Сообщение об ошибке: { "email": [ "Пользователь с таким адресом электронной почты уже существует". ], "status_code": 400 }

Модель пользователя: class User(AbstractBaseUser, PermissionsMixin): """ Модель пользователя """

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    email = models.EmailField(_("email address"), unique=True)
    name = models.CharField(_("name"), max_length=30, blank=True)

    def validate_email(self):
       email = self.email
       valid_email = email is not None and email.endswith(self.email_domain)
       if not valid_email:
           raise ValidationError(
               _("Email is not valid"),
               code="invalid.email",
           )

       if Users.objects.filter(email=email).exists():
           import ipdb; ipdb.sset_trace() #does not get called 
           raise EmailExists()

Код UserViewSet:

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """

    serializer_class = UserSerializer
    permission_classes = (IsAuthenticated,)

    def get_serializer_class(self):
        if self.action == 'list':
            return UserSerializer
        else:
            return UserDetailSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except EmailExists:
            logger.debug('caught the existing email')
            import ipdb; ipdb.sset_trace()
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

пользовательское исключение:

   from rest_framework.exceptions import ValidationError

   class EmailExists(ValidationError):
      """Raised when user exists"""
      pass

Ловите исключение с помощью ValidationError

try:
    serializer.is_valid(raise_exception=True)
except ValidationError:
    logger.debug('caught the existing email')
    import ipdb; ipdb.sset_trace()

Вместо этого вам нужно перехватить исключение ValidationError. Причина в том, что вы определили свое поле электронной почты unique=True и Django автоматически проверит его при вызове serializer.is_valid().

Кроме того, вы можете проверить ошибку уникального ограничения с помощью exc. get_full_details()

try:
    serializer.is_valid(raise_exception=True)
except ValidationError as exc:
    errors = exc.get_full_details()
    if 'email' in errors and errors['email']['code'] == 'unique':
        # do something, maybe re-raise with your custom exception:
        raise EmailExists from exc

Ref

Вернуться на верх