验证可以,但登录不行。它卡在待处理状态。

huangapple go评论59阅读模式
英文:

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:

  1. Ensure URL Configuration: Make sure that your URL configuration correctly maps to the login_user and register_user views in your members app. Check your urls.py file to verify the URL patterns.

  2. 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 using request.POST['email'] and request.POST['password']. Ensure these field names exist in your HTML forms.

  3. Authentication Backend: Ensure that you have set the authentication backend correctly in your Django settings. The default is usually 'django.contrib.auth.backends.ModelBackend'.

  4. 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 the authenticate function and any errors it might be returning.

  5. User Model: Verify that your custom Patient model and manager (PatientManager) are set up correctly. Check that the USERNAME_FIELD and REQUIRED_FIELDS attributes are defined properly.

  6. 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.

  7. 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.

  8. 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.

  9. Database Integrity: Ensure that your database schema matches the expected fields in your models.

  10. 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) &lt; (value.month, value.year))
)
if age &lt; 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):
# &hellip;
email = models.EmailField(
max_length=255,
<b>unique=True,</b>
validators=[
EmailValidator(
message=&quot;Please enter a valid email address in the format&quot;
),
RegexValidator(
regex='^name@name.name',
inverse_match=True,
message=&quot;Please provide a valid email address.&quot;,
),
],
)
birth_date = models.DateField(null=False, <b>validators=[at_least_age_18]</b>)
# &hellip;

objects = PatientManager()

USERNAME_FIELD = &#39;email&#39;
REQUIRED_FIELDS = [&#39;password&#39;]

def __str__(self):
    return self.email

# &lt;b&gt;no&lt;/b&gt; save override&lt;/code&gt;&lt;/pre&gt;

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.

huangapple
  • 本文由 发表于 2023年5月14日 02:28:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76244305.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定