基于Django自定义表单的用户登录异常问题求助
问题:自定义用户模型登录失败(注册后可正常登录,单独登录报错)
问题描述
基于UserCreationForm和AuthenticationForm实现自定义注册、登录表单,用户注册后可立即自动登录,但单独进入登录页面输入正确账号密码时,始终返回错误:{'invalid_login': '请输入正确的%(username)s和密码。注意两个字段都区分大小写。', 'inactive': '该账户未激活。'}
相关代码
models.py
from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): profile_image = models.ImageField(upload_to='accounts/images', default='default/user.jpg', blank=True, null=True) address = models.CharField(max_length=130, null=True, blank=True) date_of_birth = models.DateField(null=True, blank=True) def __str__(self) -> str: return f"{self.username}, {self.email}"
forms.py
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from .models import User import django.forms as forms class LoginForm(AuthenticationForm): class Meta: model = User fields = ['username', 'password'] labels = { 'username': "Username", 'password': 'Password' } class RegisterForm(UserCreationForm): profile_image = forms.ImageField(required=False) address = forms.CharField(max_length=130, required=False) date_of_birth = forms.DateField(required=False) class Meta: model = User fields = ['username', 'email', 'password1', 'password2', 'profile_image', 'address', 'date_of_birth'] labels = { 'username': "Ім'я користувача", 'email': 'Електронна пошта', 'password1': 'Пароль', 'password2': 'Підтвердження пароля', 'profile_image': 'Ваше фото', 'address': 'Адреса проживання', 'date_of_birth': 'Дата народження' }
views.py
from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.views import View from .forms import RegisterForm, LoginForm class RegisterView(View): def get(self, request): form = RegisterForm() return render(request, 'accounts/register.html', {'form': form}) def post(self, request): form = RegisterForm(request.POST) if form.is_valid(): user = form.save(commit=False) username = form.cleaned_data.get('username') raw_password = form.cleaned_data.get('password2') user.set_password(raw_password) user.save() authenticated_user = authenticate(username=username, password=raw_password) if authenticated_user is not None: login(request, authenticated_user) return redirect('blog:index') print(f"Form errors: {form.errors}") return render(request, "accounts/register.html", {'form': form}) class LoginView(View): def get(self, request): form = LoginForm() return render(request, 'accounts/login.html', {'form': form}) def post(self, request): form = LoginForm(request.POST) if form.is_valid(): username = form.cleaned_data.get('username') password = form.cleaned_data.get('password') user = authenticate(username=username, password=password) if user is not None: login(request, user) print(f"User {username} login successfully.") return redirect('blog:index') print(f"Form errors: {form.error_messages}") return render(request, 'accounts/login.html', {'form': form})
login.html 模板
{% extends 'base.html' %} {% block title %} Login user {% endblock %} {% block content %} <div> <form action="" method="post"> {% csrf_token %} {{ form }} <br> <button type="submit">Log in</button> </form> </div> {% endblock %}
原因分析
- LoginForm实例化错误:
AuthenticationForm构造函数需要接收request作为第一个参数,原代码中LoginForm(request.POST)未传入request,导致表单内部验证逻辑(如用户状态检查、会话验证)无法正常执行。 - 重复验证冲突:原LoginView中手动调用
authenticate,但AuthenticationForm本身已内置用户验证逻辑,重复操作可能导致状态不一致。 - LoginForm定义冗余:
AuthenticationForm并非ModelForm,无需设置Meta类指定model和fields,冗余配置会干扰表单默认行为。
解决方案
1. 修正LoginForm定义
去掉冗余的Meta类,直接自定义字段标签:
class LoginForm(AuthenticationForm): username = forms.CharField(label="用户名") password = forms.CharField(label="密码", widget=forms.PasswordInput)
2. 修改LoginView的post方法
实例化LoginForm时传入request参数,利用表单内置验证逻辑:
class LoginView(View): def get(self, request): form = LoginForm() return render(request, 'accounts/login.html', {'form': form}) def post(self, request): # 传入request和POST数据 form = LoginForm(request, data=request.POST) if form.is_valid(): # 通过表单的get_user()方法获取验证后的用户 user = form.get_user() login(request, user) print(f"User {user.username} 登录成功") return redirect('blog:index') # 此时form.errors会包含具体错误信息,可传递给模板展示 print(f"表单错误: {form.errors}") return render(request, 'accounts/login.html', {'form': form})
3. 确认settings.py配置
确保已指定自定义用户模型:
# settings.py AUTH_USER_MODEL = 'accounts.User'
4. 可选:优化RegisterView(移除冗余代码)
UserCreationForm的save()方法已自动处理密码哈希,无需手动调用set_password:
class RegisterView(View): def post(self, request): form = RegisterForm(request.POST, request.FILES) # 上传头像需要加上request.FILES if form.is_valid(): user = form.save() login(request, user) # 直接登录,无需再次authenticate return redirect('blog:index') print(f"表单错误: {form.errors}") return render(request, "accounts/register.html", {'form': form})
内容的提问来源于stack exchange,提问作者Bohdan
相关产品推荐
相关产品推荐

