Django3.0自定义用户模型authenticate返回None问题排查求助
问题分析与解决方案
首先,你的代码里有两个关键问题导致authenticate()始终返回None,咱们一步步来解决:
1. 用户管理器里的递归调用错误
在AccountManager的create_user方法中,你错误地用self.create_user()来创建用户实例——这是递归调用自己,会导致代码根本走不到set_password()那一步!最终密码没有被正确哈希存储(甚至等于没设置密码),这直接导致authenticate()无法匹配验证。
修复方法:
把创建用户实例的代码改成self.model()(这是BaseUserManager提供的标准方法,用来获取当前管理器对应的用户模型):
class AccountManager(BaseUserManager): def create_user(self, email, username, password=None): if not email: raise ValueError("Email Id not entered") if not username: raise ValueError("User Name not entered") # 替换递归调用为self.model()创建实例 user = self.model( email=self.normalize_email(email), username=username, ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, username, password): user = self.create_user( email=self.normalize_email(email), password=password, username=username, ) user.is_admin = True user.is_staff = True user.is_superuser = True user.save(using=self._db) return user
2. 登录视图的表单验证语法错误
在login视图里,你写了if form.is_valid——这其实是在判断is_valid这个方法对象是否存在(永远为True),而不是真正执行表单验证逻辑。正确的写法是调用方法form.is_valid()。
修复方法:
修改登录视图中的判断逻辑:
def login(request): context = {} if request.method == "POST": form = AuthenticationForm(request.POST) # 修复:添加括号调用is_valid()方法 if form.is_valid(): name = request.POST["username"] pswd = request.POST["password"] user = authenticate(request, username=name, password=pswd) print("user = " + str(user)) if user: print("valid user " + str(user)) login(request, user) print("user is " + str(request.user.is_authenticated)) return redirect("../dashboard/") form = AuthenticationForm() context['login_form'] = form return render(request, 'login.html', context)
额外优化建议
AuthenticationForm默认是为Django内置的User模型设计的,对于自定义用户模型,最好创建一个适配的表单子类,避免潜在问题:
from django.contrib.auth.forms import AuthenticationForm from .models import Account class CustomAuthenticationForm(AuthenticationForm): class Meta: model = Account fields = ['username', 'password']
之后在登录视图里替换成这个自定义表单即可:
form = CustomAuthenticationForm(request.POST)
验证修复效果
- 先删除之前注册的测试用户(因为它们的密码是明文存储的,不符合规范)
- 重新注册一个用户
- 尝试登录,此时
authenticate()应该能正确返回用户实例了
另外你提到Account.objects.get(username="uname").password和request.POST['password']对比为True,这正好说明之前的密码是明文存储的(因为set_password()没执行),修复后数据库里的密码会变成哈希值,此时直接对比就不会相等了——这才是正确的安全状态。
内容的提问来源于stack exchange,提问作者Suraj Ingle
相关产品推荐
相关产品推荐

