Search code examples
djangodjango-rest-frameworkdjango-authenticationdjango-rest-viewsetsdjango-rest-framework-jwt

Custom error message on Create User on DRF ModelViewSet


I'm writing a Django Rest API using Django Rest Framework and in it I have a base custom user User and two kinds of user that inherit from User, Doctor and Pacient.

Each one has a different endpoint, so to create a Doctor we make a POST request to /api/v1/doctor and to create a Paciente, a POST to api/v1/pacient/.

If I try creating a user (using those endpoints) but with an e-mail that is already registered (I have changed Django to use e-mail instead), I get the following.

{
    "email": [
        "user with this email already exists."
    ]
}

What I'm trying to achieve is to change this error message, but not only change, I need to verify if the e-mail if from a Pacient or Doctor regardless of which endpoint I'm using, so I can display different messages for each case.

PacientViewSet (DoctorViewSet is basically the same) :

class PacientViewSet(viewsets.ModelViewSet):
    serializer_class = PacientSerializer
    queryset = Pacient.objects.all()
    permission_classes = (AllowAny, )

Serializer:

class PacientSerializer(serializers.ModelSerializer):
    def create(self, validated_data):
        user = Paciente.objects.create_paciente_user(
            nome_completo=self.validated_data['full_name'],
            password=self.validated_data['password'],
            email=self.validated_data['email'],
        )
        return user

    class Meta:
        model = Pacient
        fields = ('id', 'email', 'password', 'full_name', ...)
        extra_kwargs = {
            'password': {
                'write_only': True,
            }
        }

Please let me know if there's something else I need to share.

EDIT:

class CustomUser(AbstractBaseUser, PermissionsMixin):
    full_name = models.CharField(max_length=100, null=True, blank=True)
    email = models.EmailField(_('email address'), unique=True)

    SEX_CHOICES = [
        (ConstantesSexo.MALE, 'Male'),
        (ConstantesSexo.FEMALE, 'Female'),
    ]
    sex = models.CharField(max_length=1, choices=SEX_CHOICES, null=True, blank=True)

    is_staff = models.BooleanField(_('staff status'), default=False)
    is_active = models.BooleanField(_('active'), default=True)

    created = models.DateTimeField(_('date joined'), default=timezone.now)
    modified = models.DateTimeField(auto_now=True)

    username_validator = UnicodeUsernameValidator()
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        blank=True,
        null=True,
        validators=[username_validator],
        error_messages={
            'unique': _("Username already exists."),
        },
    )
    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    USER_CHOICES = [
        (UserType.DOCTOR, 'Doctor'),
        (UserType.PACIENT, 'Pacient'),
    ]
    user_type = models.CharField(max_length=3, choices=USER_CHOICES)


class Pacient(CustomUser):
    nome_social = models.CharField(blank=True, null=True, max_length=50)


class Doctor(CustomUser):
    doctor_id = models.CharField(max_length=50)
    bio = models.TextField(blank=True, null=True)
    verified = models.DateTimeField(null=True, blank=True)


Solution

  • In the end I solved it by overriding the create method in the ModelViewSet (not in the serializer):

    class DoctorViewSet(viewsets.ModelViewSet):
    
        def create(self, request, *args, **kwargs):
            email = request.data.get('email')
            user = CustomUser.objects.filter(email=email).first()
            if email and user:
                if user.is_doctor():
                    error_msg = 'doctor error msg'
                elif user.is_pacient():
                    error_msg = 'pacient error msg'
                return Response({'error': error_msg}, status=status.HTTP_400_BAD_REQUEST)
    
            return super().create(request, *args, **kwargs)