The issue is as explained in the title. I am able to create and authenticate users through forms or the cli but once the user/patient object is passed to the login(request, user) function, the entire application gets stuck and the pages keep loading. Whether I am logging in directly from the sign in page or registering a new member then trying to redirect them based on successful authentication. What could the issue be?
(Note, I attempted creating a custom auth backend that also pitfalls into the same issue as the default.) Thanks in advance.
This is a snippet of my Patient model along with its manager from the booking app
class PatientManager(BaseUserManager):
""" Manager for patient profiles """
use_in_migrations = True
def _create_user(self, email, password, is_superuser, birth_date, phone_no, **extra_fields):
""" Create a new user profile """
if not email:
raise ValueError('User must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, password=password, is_superuser=is_superuser, birth_date=birth_date, phone_no=phone_no, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
user = self._create_user(email=email, password=password, is_superuser=True, birth_date=date(1990, 1, 1), phone_no="0711111111")
return user
class Patient(AbstractUser, PermissionsMixin):
uuid = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4())
username = None
name = models.CharField(max_length=50, null=False)
email = models.EmailField(max_length=255, unique=True, validators=[EmailValidator(message="Please enter a valid email address in the format"), RegexValidator(regex='^[email protected]', inverse_match=True, message="Please provide a valid email address.")])
birth_date = models.DateField(null=False)
gender = models.CharField(choices=GENDER_CHOICES, default="Prefer Not To Say", max_length=20)
phone_no = models.IntegerField(null=False)
account_type = models.CharField(max_length=10, default='PATIENT')
kin_name = models.CharField(max_length=50, help_text="*Optional", null=True, blank=True)
kin_contact = models.IntegerField(help_text="*Optional", null=True, blank=True)
password = models.CharField(max_length=30, validators=[MinLengthValidator(limit_value=8, message="Please ensure the password is at least 8 characters"), RegexValidator(regex='^password', inverse_match=True, message="Please use a different password")], default="password")
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_update = models.DateTimeField(_('last updated'), auto_now=True)
objects = PatientManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def __str__(self):
return self.email
def save(self, *args, **kwargs):
while True:
if (datetime.today().date() - self.birth_date).days < 6390:
raise ValidationError(f"You are a {(datetime.today().date() - self.birth_date).days} year old. Account holders should be adults who have attained at least 18 years of age.")
if Patient.objects.filter(email = self).count() < 1:
break
super().save(*args, **kwargs)
This is a snippet of my members app views.py
def login_user(request):
if request.method == "POST":
username = request.POST['email']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user:
print(f"{username} {password} is being logged in as\n {user} {request.POST}")
login(request, user)
print(f"Has been authenticated {user}")
# Redirect to a success page.
return redirect('index')
else:
# Return an 'invalid login' error message.
messages.error(request, "There Was An Error!")
return redirect('login')
else:
return render(request, 'authenticate/login.html', {})
def register_user(request):
if request.method == "POST":
form = RegisterUserForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['email']
password = form.cleaned_data['password1']
print(f"{username} {password}")
user = authenticate(username=username, password = password)
print(f"{user}")
login(request, user)
messages.success(request, "Sign Up Completed!")
return redirect('index')
else:
form = RegisterUserForm()
return render(request, 'authenticate/register_user.html', {
'form':form,
})
I was hoping once the user gets authenticated they would get redirected to the index page. I have logged output from the cli and this proves that the users are authenticated but my login function is buggy. This result below is from: print(f"{username} {password} is being logged in as\n {user} {request.POST}")
[email protected] @octo808 is being logged in as
[email protected] <QueryDict: {'csrfmiddlewaretoken': ['7NVGmhwyH2J2tT07jtt6SKNhOWyJl9xYUWlCtjL6lX5hJrjIvpJ7Edth8is3GAxp'], 'email': ['[email protected]'], 'password': ['@octo808']}>
EDIT: I have included the register module from my views. I have also noticed that the user_logged_in signal from django\contrib\auth\__init__.py never fires up in the login function.
user_logged_in.send(sender=user.__class__, request=request, user=user)
Likely the
save()method is a culprit: it can get in an infinite loop, and actually quite fast.Indeed, if you save the
Personagain, then for the queryPatient.objects.filter(email = self).count()it will return one record, indeed, the one record you are saving again.But regardless, enforcing uniqueness with queries is inefficient and inelegant anyway. You can do this through validators, you already marked
emailasunique=True, so normally the database will handle this. For the birthday, you can work with:Nice thing is that Django's
ModelForms will also look for the validators of the fields, and thus print the error in the corresponding field if people fill in a birthday that is less than 18 years ago.