I created a custom user Model, that uses the Email field as the username.
Also I had to create a Custom backend to validate as Case Insensitive the email field. The Registration page works perfectly fine, but when I try to login with a user that is not created I get this error:
Environment:
Request Method: POST
Request URL: http://localhost:8000/members/login/
Django Version: 3.1.4
Python Version: 3.8.6
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'home',
'projects',
'about',
'blog',
'contact',
'members',
'ckeditor',
'django_bleach']
Installed 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']
Traceback (most recent call last):
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/DeveloperRoad/members/backends.py", line 14, in authenticate
user = UserModel._default_manager.get(**{case_insensitive_user_name_field: username})
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/db/models/query.py", line 429, in get
raise self.model.DoesNotExist(
During handling of the above exception (BlogUser matching query does not exist.), another exception occurred:
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
return view(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
return bound_method(*args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/contrib/auth/views.py", line 63, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch
return handler(request, *args, **kwargs)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/views/generic/edit.py", line 141, in post
if form.is_valid():
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/forms/forms.py", line 177, in is_valid
return self.is_bound and not self.errors
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/forms/forms.py", line 172, in errors
self.full_clean()
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/forms/forms.py", line 375, in full_clean
self._clean_form()
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/forms/forms.py", line 402, in _clean_form
cleaned_data = self.clean()
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/contrib/auth/forms.py", line 215, in clean
self.user_cache = authenticate(self.request, username=username, password=password)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/venv/lib/python3.8/site-packages/django/contrib/auth/__init__.py", line 73, in authenticate
user = backend.authenticate(request, **credentials)
File "/home/daniel/MEGA/my-git/github/Developer-Road-Website/Developer-road-website/DeveloperRoad/members/backends.py", line 17, in authenticate
UserModel.set_password(password)
Exception Type: TypeError at /members/login/
Exception Value: set_password() missing 1 required positional argument: 'raw_password'
Here is the Custom User Model and its manager:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
# Used to create the Custom User and it's manager
class BlogUserManager(BaseUserManager):
"""
Manage the blog user, email is the login identifier and first name and last name are mandatory
"""
def create_user(self, email, first_name, last_name, password=None):
"""
Create and save an User with the given EMAIL, FIRST_NAME, LAST_NAME and Password.
"""
if not email:
raise ValueError("Blog user must have an email address")
if not first_name:
raise ValueError("Blog user must have a First name")
if not last_name:
raise ValueError("Blog user must have a Last name")
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, first_name, last_name, password=None):
"""
Create and save an Super User with the given EMAIL, FIRST_NAME, LAST_NAME and Password.
"""
user = self.create_user(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
password=password
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
def get_profile_image_filepath(self):
"""
Returns the profile name path to store
"""
return f"images/profile_images/{self.pk}/profile_image.png"
def get_default_profile_image():
"""
Returns the default profile image
"""
return "images/default_profile_image/default.svg"
# Custom User Model
class BlogUser(AbstractBaseUser):
"""
Basic Custom User for the Blog
"""
username = None
email = models.EmailField(verbose_name="email", max_length=70, unique=True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
date_joined = models.DateTimeField(
verbose_name="date_joined", auto_now_add=True)
last_login = models.DateTimeField(verbose_name="last_login", auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
profile_image = models.ImageField(max_length=255, upload_to=get_profile_image_filepath,
default=get_default_profile_image, blank=True, null=True)
hide_email = models.BooleanField(default=True)
objects = BlogUserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["first_name", "last_name"]
def __str__(self):
return str(self.first_name) + " " + str(self.last_name)
def get_profile_image_filename(self):
"""
Return the profile image filename
"""
image = str(self.profile_image)
return image[image.index(f"profile_images/{self.pk}/"):]
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
And here is the custom backend that generates the error:
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class CaseModelBackend(ModelBackend):
"""
Fix the problem of the login with insensitive email.
"""
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
case_insensitive_user_name_field = f"{UserModel.USERNAME_FIELD}__iexact"
user = UserModel._default_manager.get(**{case_insensitive_user_name_field: username})
except UserModel.DoesNotExist:
UserModel.set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
What can I do?