0
votes

I have created a custom user class which appears to be working correctly however whenever I try to log in to the admin, I keep getting the following error on the login page:

Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive.

I have already created several superuser which are all saving to the DB correctly with the is_staff/is_superuser/is_active flags set to True as you can see below:

CustomUser.objects.all().values()
<QuerySet [{'id': 1, 'password': 'test', 'last_login': None, 'is_superuser': True, 'username': 'test1', 'first_name': '', 'last_name': '', 'email': '[email protected]', 'is_staff': True, 'is_active': True, 'date_joined': datetime.datetime(2020, 6, 1, 0, 17, 30, 297149, tzinfo=<UTC>), 'role_id': 1, 'user_type_id': 1, 'created_by_id': None, 'update_date': datetime.datetime(2020, 6, 1, 0, 17, 30, 298524, tzinfo=<UTC>), 'updated_by_id': None}]>

I am officially puzzled as to what I have done incorrectly... Please help me figure this one out...

models.py:

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


class UserType(models.Model):
    """
    This model defines the types of users which are allowed to be created in the application. Examples include:
    API Read Only User
    API Full CRUD User
    Business User
    """
    name = models.CharField(max_length=50, blank=False, null=False)
    description = models.TextField()
    active = models.BooleanField(default=True)
    creation_date = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='user_type_created_by')
    update_date = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='user_type_updated_by')


class Role(models.Model):
    """
    This model defines the job code/organization role a particular user is related to within their organization.
    Examples include:
    System User
    Business User
    Business User Manager
    """
    name = models.CharField(max_length=50)
    description = models.TextField()
    active = models.BooleanField(default=True)
    creation_date = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='role_created_by')
    update_date = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='role_updated_by')


class CustomBaseUserManager(BaseUserManager):
    """
    Defined a custom base user manager class so as operations are executed against the CustomUser model, application
    specific fields can be utilized.
    """

    def create_user(self, role, user_type, username=None, email=None, password=None):
        # Verify that email was submitted
        if not email:
            raise ValueError('Email is required to create a user')
        else:
            email = BaseUserManager.normalize_email(email)

        # If no username was submitted but email was, assign email to the username
        if not username:
            username = email

        # Validate and get role ID from Role model
        role = Role.objects.get(id=role, active=True)

        # Validate and get the user_type ID from UserType model
        user_type = UserType.objects.get(id=user_type, active=True)

        user = self.model(
            email=email,
            username=username,
            role=role,
            user_type=user_type
        )

        user.set_password(password)
        user.save(using=self._db)

        return user

    def create_superuser(self, role, user_type, username=None, email=None, password=None):

    # Verify that email was submitted
        if not email:
            raise ValueError('Email is required to create a user')
        else:
            email = BaseUserManager.normalize_email(email)

    # If no username was submitted but email was, assign email to the username
        if not username:
            username = email

        # Validate and get role ID from Role model
        role = Role.objects.get(id=role, active=True).id

        # Validate and get the user_type ID from UserType model
        user_type = UserType.objects.get(id=user_type, active=True).id

        user = self.create_user(
            email=email,
            username=username,
            role=role,
            user_type=user_type
        )

        user.is_staff = True
        user.is_superuser = True
        user.is_active = True
        user.is_admin = True
        user.set_password(password)
        user.save(using=self._db)

        return user


class CustomUser(AbstractUser):
    """
    This is a custom user model allowing for the required relationship between a user and a specific role as defined
    by the organization. The only roles which will be allowed to be assigned to users are those which are active at the
    time the user is being created.
    """

    role = models.ForeignKey(Role, on_delete=models.DO_NOTHING, limit_choices_to={'active': True}, null=False,
                             blank=False)
    user_type = models.ForeignKey(UserType, on_delete=models.DO_NOTHING, limit_choices_to={'active': True}, null=False,
                                  blank=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='user_created_by')
    update_date = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, null=True, blank=True,
                                   related_name='user_updated_by')

    objects = CustomBaseUserManager()

    REQUIRED_FIELDS = AbstractUser.REQUIRED_FIELDS + [
        'role',
        'user_type'
    ]

    def get_full_name(self):
        """
        Return the first_name plus the last_name, with a space in between.
        """
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def __str__(self):
        return '{} <{}>'.format(self.get_full_name(), self.email)

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

settings.py:

"""
Django settings for CategoryManager project.

Generated by 'django-admin startproject' using Django 3.0.6.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

SESSION_COOKIE_DOMAIN = '127.0.0.1:8000/'

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'l%sn*03#ls^d6e5e-&)u93lyqzvh$bh1nij)ye2h4la$&jz^t!'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Users',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'CategoryManager.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'CategoryManager.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Custom user definition
AUTH_USER_MODEL = 'Users.CustomUser'

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

AUTHENTICATION_BACKENDS = (
    # Needed to login by custom User model, regardless of `allauth`
    "django.contrib.auth.backends.ModelBackend",
)

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

SOLVED: Turns out there was some issue in my local cache which was preventing django from being able to actually allow me to log in. Once I cleared my cache locally, I was able to log in.

2
Note that the value of password field should be a string encrypted.Blackdoor
Updated the code here's the latest user: {'id': 2, 'password': 'pbkdf2_sha256$180000$VO261BdKXNcY$9xAYS6j1Ry0dfCw2S2ghE+fK83/jBD3tF+Bf9I3lDUA=', 'last_login': datetime.datetime(2020, 6, 1, 3, 9, 50, 522421, tzinfo=<UTC>), 'is_superuser': True, 'username': 'test3', 'first_name': '', 'last_name': '', 'email': '[email protected]', 'is_staff': True, 'is_active': True, 'date_joined': datetime.datetime(2020, 6, 1, 3, 9, 19, 294674, tzinfo=<UTC>), 'role_id': 1, 'user_type_id': 1, 'created_by_id': None, 'update_date': datetime.datetime(2020, 6, 1, 3, 9, 19, 385517, tzinfo=<UTC>), 'updated_by_id': None}brandonris1

2 Answers

0
votes

under create_superuser method change user=self.model to user=self.create_user

0
votes

SOLVED: Turns out there was some issue in my local cache which was preventing django from being able to actually allow me to log in. Once I cleared my cache locally, I was able to log in.