0
votes

I just create a Custom User Model with Django for Django Rest Framework, I create the generics.ListAPIView to get the list of User and Create New User Then I create the Login View with views.APIView with overridden post() with validation. But when I clicked the "POST", its return the "User already exists". Why the login method tried to create an account even when i use django-rest-auth?

Thanks in advance

here is the code

models.py

class AccountManager(BaseUserManager):
    def create_user(self, email, first_name=None, last_name=None, password=None, is_active=True, is_staff=False, is_admin=False, is_superuser=False):
        if not email:
            raise ValueError("User must have an email address")
        if not password:
            raise ValueError("User must have a password")
        if not first_name:
            raise ValueError("User must have a first name")
        user = self.model(
                email=self.normalize_email(email)
            )
        user.set_password(password)
        user.first_name = first_name
        user.last_name = last_name
        user.staff = is_staff
        user.admin = is_admin
        user.active = is_active
        user.superuser = is_superuser
        user.save(using=self._db)
        return user

    def create_superuser(self, email, first_name=None, last_name=None, password=None):
        user = self.create_user(
                email=email,
                first_name = first_name,
                last_name = last_name,
                password=password,
                is_superuser=True,
                is_staff=True,
                is_admin=True,

            )
        return user

class Account(AbstractBaseUser):
    email       =models.EmailField(max_length=255, unique=True)
    first_name  = models.CharField(max_length=255,default='')
    last_name   = models.CharField(max_length=255, default='')
    active      = models.BooleanField(default=True)
    staff       = models.BooleanField(default=False)
    admin       = models.BooleanField(default=False)
    superuser   = models.BooleanField(default=False)
    created_data = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(auto_now=True)

    #USERNAME_FIELD and password are required by default
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name']

    objects = AccountManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return (self.first_name + self.last_name)

    def get_short_name(self):
        return self.first_name

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    @property
    def is_admin(self):
        return self.admin

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_superuser(self):
        return self.superuser

serializers.py

class AccountRegistrationSerializer(serializers.ModelSerializer):
    # password = serializers.CharField(style={'input_type':'password'}, write_only=True)
    password2 = serializers.CharField(style={'input_type':'password'}, write_only=True)
    class Meta:
        model = Account
        extra_kwargs = {
                    'password': {'write_only': True}
        }
        fields = ['email', 'first_name', 'last_name','password', 'password2',]

    def create(self, validated_data):
        account = Account(
            email=self.validated_data['email'],
            first_name=self.validated_data['first_name'],
            last_name=self.validated_data['last_name']
            )
        password = self.validated_data['password']
        password2 = self.validated_data['password2']

        if password != password2:
            raise serializer.ValidationError({'password':'Passwords must match'})
        account.set_password(password)
        account.save()
        return account

class AccountLoginSerializer(serializers.ModelSerializer):

    class Meta:
        model = Account
        extra_kwargs = {
            'password': {
                'write_only': True
            },
            'first_name': {
                'read_only': True
            },
            'last_name': {
                'read_only': True
            },

        }
        fields = ['email', 'first_name', 'last_name', 'password']

    def validate(self, data):
        return data

views.py

class AccountLoginView(APIView):
    permission_classes = [AllowAny,]
    serializer_class = AccountLoginSerializer
    def post(self, request, *args, **kwargs):
        data = request.data
        serializer = AccountLoginSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            new_data = serializer.data
            return Response(new_data, status=HTTP_200_OK)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
1
It looks like you are not logging in, but creating a new user. - Willem Van Onsem
I expected it will return the data. Or the serializer.is_valid will give us to create user as default? - CH Andre Mailoa
did you specify your custom user model as default user model in settings.py? AUTH_USER_MODEL = 'app.Account' - uedemir
yes, i am AUTH_USER_MODEL = 'account.Account' - CH Andre Mailoa
It's possible that this happen due to I use ModelSerializer for Login, so the serializer.is_valid() will refer to account creation models? - CH Andre Mailoa

1 Answers

0
votes

it's been 5 days since I asked this question. I have solved this problem by override to_internal_value method and validate the serializers.

serializer.py

def to_internal_value(self, data):   
    try:
        try:
            email = data["email"]
            user = Account.objects.filter(email=email)
            return data
        except KeyError:
            raise serializers.ValidationError({'email':'Please Input your Email'})
        except ValueError:
            raise serializers.ValidationError({'email':'Email Not Valid'})
    except Account.DoesNotExist:
        raise serializers.ValidationError({'error':'Database Error'})

def validate(self, data):
    user_obj=None
    email = data.get('email', None)
    password = data.get('password', None)
    if not email and not username:
        raise ValidationError({"error":"Need to be filled"})

    user = Account.objects.filter(
            Q(email=email)
        ).distinct()
    user = user.exclude(email__isnull=True).exclude(email__iexact='')
    if user.exists() and user.count() == 1:
        user_obj = user.first()
    else:
        raise ValidationError({"email":"Not valid"})
    if user_obj:
        if not user_obj.check_password(password):
            raise ValidationError({"password":"Incorrect credentials please try again"})
    new_data = user_obj
    return new_data