英文:
Authenticate works but login does not. It's stuck on pending
问题
The issue you are facing seems to be related to the login process in your Django application. Without a detailed analysis, it's challenging to pinpoint the exact problem. However, I can offer some suggestions to help you troubleshoot:
-
Ensure URL Configuration: Make sure that your URL configuration correctly maps to the
login_user
andregister_user
views in yourmembers app
. Check yoururls.py
file to verify the URL patterns. -
Verify Form Fields: Double-check that the form fields in your login and registration templates match the expected field names in your views. In your
login_user
view, you are usingrequest.POST['email']
andrequest.POST['password']
. Ensure these field names exist in your HTML forms. -
Authentication Backend: Ensure that you have set the authentication backend correctly in your Django settings. The default is usually
'django.contrib.auth.backends.ModelBackend'
. -
Debug Logging: Continue to use
print
statements or better yet, Django's built-in logging functionality, to trace the execution flow. This will help you identify where the code might be failing. Pay special attention to theauthenticate
function and any errors it might be returning. -
User Model: Verify that your custom
Patient
model and manager (PatientManager
) are set up correctly. Check that theUSERNAME_FIELD
andREQUIRED_FIELDS
attributes are defined properly. -
User Registration: Ensure that the user registration process is creating users correctly. You might want to log the user object after registration to make sure it's created successfully.
-
Signals: If the
user_logged_in
signal is not firing as expected, double-check that you are using the correct signal and that it's properly connected. You can add some debugging statements within your signals to see if they are being triggered. -
Check Middleware: Check if any custom middleware in your Django project might be interfering with the login process. Temporarily disabling middleware can help identify if this is the issue.
-
Database Integrity: Ensure that your database schema matches the expected fields in your models.
-
Error Handling: Implement proper error handling in your views to catch any exceptions that might be occurring during the login process. This will help you get more detailed error messages.
By systematically checking these areas and using debugging techniques, you should be able to identify and resolve the issue with your Django authentication process.
英文:
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='^name@name.name', 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}")
t@a.com @octo808 is being logged in as
t@a.com <QueryDict: {'csrfmiddlewaretoken': ['7NVGmhwyH2J2tT07jtt6SKNhOWyJl9xYUWlCtjL6lX5hJrjIvpJ7Edth8is3GAxp'], 'email': ['t@a.com'], '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)
答案1
得分: 1
The translation of the provided text is as follows:
可能save()
方法是问题的源头:它可能陷入无限循环,并且非常迅速。
实际上,如果再次保存Person
,然后对于查询Patient.objects.filter(email=self).count()
,它将返回一条记录,确实是您再次保存的那条记录。
但无论如何,使用查询来强制唯一性是低效且不优雅的。您可以通过验证器来完成这个任务,您已经将email
标记为unique=True
,所以通常数据库会处理这个问题。对于生日,您可以使用以下方法:
from datetime import date
def at_least_age_18(value):
today = date.today()
age = (
today.year
- value.year
- ((today.month, today.day) < (value.month, value.year))
)
if age < 18:
raise ValidationError(
f'You are a {age} year old. Account holders should be adults who have attained at least 18 years of age.'
)
class Patient(AbstractUser, PermissionsMixin):
# ...
email = models.EmailField(
max_length=255,
unique=True,
validators=[
EmailValidator(
message="Please enter a valid email address in the format"
),
RegexValidator(
regex='^name@name.name',
inverse_match=True,
message="Please provide a valid email address.",
),
],
)
birth_date = models.DateField(null=False, validators=[at_least_age_18])
# ...
objects = PatientManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def __str__(self):
return self.email
# no save override
有趣的是,Django的ModelForm
也会查找字段的验证器,因此如果人们填写的生日少于18岁,它将在相应字段中显示错误。
英文:
Likely the save()
method is a culprit: it can get in an infinite loop, and actually quite fast.
Indeed, if you save the Person
again, then for the query Patient.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 email
as unique=True
, so normally the database will handle this. For the birthday, you can work with:
<pre><code>from datetime import date
def <b>at_least_age_18</b>(value):
today = date.today()
age = (
today.year
- value.year
- ((today.month, today.day) < (value.month, value.year))
)
if age < 18:
raise ValidationError(
f'You are a {age} year old. Account holders should be adults who have attained at least 18 years of age.'
)
class Patient(AbstractUser, PermissionsMixin):
# …
email = models.EmailField(
max_length=255,
<b>unique=True,</b>
validators=[
EmailValidator(
message="Please enter a valid email address in the format"
),
RegexValidator(
regex='^name@name.name',
inverse_match=True,
message="Please provide a valid email address.",
),
],
)
birth_date = models.DateField(null=False, <b>validators=[at_least_age_18]</b>)
# …
objects = PatientManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def __str__(self):
return self.email
# <b>no</b> save override</code></pre>
Nice thing is that Django's ModelForm
s 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论