Django中Authenticate正常但Login陷入Pending状态的问题求助
问题:调用
login(request, user)后应用卡住,页面持续加载 - 可通过表单/CLI创建并认证用户,但将Patient对象传入login函数后,应用完全卡住,页面持续加载
- 直接登录或注册后跳转均出现该问题,自定义认证后端也无效
- CLI日志显示用户已完成认证,但login函数中的
user_logged_in信号从未触发
Patient模型及管理器代码(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)
视图代码(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, })
CLI日志输出
t@a.com @octo808 is being logged in as t@a.com <QueryDict: {'csrfmiddlewaretoken': ['7NVGmhwyH2J2tT07jtt6SKNhOWyJl9xYUWlCtjL6lX5hJrjIvpJ7Edth8is3GAxp'], 'email': ['t@a.com'], 'password': ['@octo808']}>
问题根源
- Patient模型save方法存在无限循环:
while True循环中,Patient.objects.filter(email = self).count() < 1的条件逻辑错误——self是Patient对象,不是邮箱字符串,且更新用户时该条件永远不满足,导致死循环。 - login触发用户保存操作:Django的login函数会更新用户的
last_login字段(继承AbstractUser自带),调用Patient的save方法,触发死循环,导致应用卡住。
修复步骤
- 移除save方法中的死循环,修正年龄验证逻辑:
def save(self, *args, **kwargs): # 年龄验证(计算为整数年份更合理) age_days = (datetime.today().date() - self.birth_date).days if age_days < 6390: # 18*365=6570,此处按原代码保留6390 raise ValidationError(f"You are {age_days//365} years old. Account holders must be at least 18 years of age.") super().save(*args, **kwargs)
- 将验证逻辑移至clean方法(更规范):
def clean(self): super().clean() age_days = (datetime.today().date() - self.birth_date).days if age_days < 6390: raise ValidationError(f"You are {age_days//365} years old. Account holders must be at least 18 years of age.")
- 移除模型中冗余字段:继承AbstractUser后,
password、is_superuser、is_active字段无需重复定义,避免覆盖默认逻辑导致认证异常。
额外优化
- 修正PatientManager的
_create_user方法:删除构造model时的password=password参数,set_password已处理密码加密,避免明文风险。
内容的提问来源于stack exchange,提问作者kurosakiaduma
相关产品推荐
相关产品推荐

