Can't login my users, they don't seem to be registering properly

Viewed 130

I'm trying to login the users I registered in my registration view (where I get a 200 code that says POST request was successful) but I get "Unable to log in with provided credentials." when I try to log them in. When I check in the shell with User.objects.all(), I only get my superuser back so I think the users are not being saved to the database. I don't understand why this is happening so if anyone has an idea, it'd be appreciated.

Here's the code.

Models:

from django.db import models, transaction
from django.conf import settings
from django.contrib.auth.models import BaseUserManager, AbstractUser


class UserManager(BaseUserManager):
    
    @transaction.atomic
    def create_user(self, email, username, password=False):
        
        if not email:
            raise ValueError('Users must have an email address')

        if not username:
            raise ValueError('Users must have an username')

        user = self.model(
            email=self.normalize_email(email),
            username=username,
        )
        user.set_password(password)
        user.save()

        return user

    def get_by_natural_key(self, username):
        return self.get(username=username)

    def create_superuser(self, username, password, email):
        
        user = self.create_user(
            username=username,
            email=email,
            password=password,
        )
        user.is_superuser = True
        user.save(using=self._db)
        return user


class User(AbstractUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )

    username = models.CharField(
        verbose_name= 'username',
        max_length= 50,
        unique=True,
    )

    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']

    def __str__(self):
        return str(self.username)

Serializers:

from django.contrib.auth.models import User
from rest_framework import serializers
from backend.models import User
from django.contrib.sites.shortcuts import get_current_site
from django.db.models import Q
from rest_framework.validators import UniqueValidator
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate, get_user_model

user = get_user_model()

class UserRegistrationSerializer(serializers.ModelSerializer):

    username = serializers.CharField(
        required=True,
        validators=[UniqueValidator(queryset=User.objects.all(),lookup='iexact')]
    )

    email = serializers.CharField(
        required=True,
        validators=[UniqueValidator(queryset=User.objects.all(),lookup='iexact')]
    )

    password = serializers.CharField(
        required=True,
        label="Password",
        style={'input_type': 'password'}
    )

    password_2 = serializers.CharField(
        required=True,
        label="Confirm Password",
        style={'input_type': 'password'}
    )

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'password_2',]

    def validate_password(self, value):
        if len(value) < 8:
            raise serializers.ValidationError(
                "Password should be at least 8 characters long.")
        return value

    def validate_password_2(self, value):
        data = self.get_initial()
        password = data.get('password')
        if password != value:
            raise serializers.ValidationError("Passwords don't match.")
        return value

    def validate_username(self, value):
        if User.objects.filter(username=value).exists():
            raise serializers.ValidationError("Username already exists.")
        return value

    def create(self, validated_data):

        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user




class UserLoginSerializer(serializers.ModelSerializer):

    username = serializers.CharField(
        required=True,
        write_only=True,
    )

    token = serializers.CharField(
        allow_blank=True,
        read_only=True
    )

    password = serializers.CharField(
        required=True,
        write_only=True,
        style={'input_type': 'password'}
    )

    class Meta(object):
        model = User
        fields = ['username', 'password', 'token']

    def validate(self, data):
        username = data.get('username', None)
        password = data.get('password', None)

        if username and password:
            user = authenticate(request=self.context.get('request'),
                                username=username, password=password)
            if not user:
                msg = 'Unable to log in with provided credentials.'
                raise serializers.ValidationError(msg, code='authorization')
        else:
            msg = "Must include username and password."
            raise serializers.ValidationError(msg, code='authorization')

        data['user'] = user
        return data

   

Views:

from django.contrib.auth import get_user_model
from django.contrib.sites.shortcuts import get_current_site
from rest_framework import generics, permissions, status 
from rest_framework.authentication import TokenAuthentication
from rest_framework.response import Response

from backend.models import User 
from backend.serializers import UserLoginSerializer, UserRegistrationSerializer
from backend import serializers

from django.contrib.auth.decorators import login_required
from rest_framework.authtoken.models import Token

User = get_user_model()

class UserLoginAPIView(generics.CreateAPIView):

    permission_classes = (permissions.AllowAny, )
    serializer_class = serializers.UserLoginSerializer

    def post(self, request, *args, **kwargs):
        serializer = UserLoginSerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        return Response({"status": status.HTTP_200_OK, "Token": token.key})

    

class UserRegistrationAPIView(generics.CreateAPIView):

    permission_classes = (permissions.AllowAny, )
    serializer_class = serializers.UserRegistrationSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid(raise_exception=True):
            return Response(serializer.data, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3 Answers

The issue was that I needed to add 'user.set_password(validated_data['password'])' right after the user. That solved it.

def create(self, validated_data):
    user = User(
        email=validated_data['email'],
        username=validated_data['username']
    )
    user.set_password(validated_data['password'])
    user.save()
    return user

Check in your settings.py file that you have configured the user model to your custom user. You should have something like this:

AUTH_USER_MODEL = 'accounts.User'

Where "accounts" is the name of the django app where you define your User model

You have to call the serializer's save method (which will call your create method) to actually create the user:

if serializer.is_valid(raise_exception=True):
    serializer.save()
    return Response(serializer.data, status=status.HTTP_200_OK)
Related