Django中无法将表单数据存入数据库且出现'type object 'UserRegister' has no attribute 'USERNAME_FIELD''错误
我看到你遇到了两个头疼的问题:表单数据存不进数据库,还抛出了type object 'UserRegister' has no attribute 'USERNAME_FIELD'的错误。让我帮你一步步排查修复:
错误核心原因
这个错误的根源是你的UserRegister模型继承了普通的models.Model,但你使用的UserCreationForm是Django专门为继承AbstractUser的自定义用户模型设计的表单类。AbstractUser内置了USERNAME_FIELD等用户认证必需的属性,而普通Model没有这些,所以才会触发这个报错。
1. 修复models.py
把UserRegister改成继承AbstractUser,这是Django自定义用户模型的标准做法:
from django.contrib.auth.models import AbstractUser from django.db import models class UserRegister(AbstractUser): # 如果你不需要额外的用户字段,这里可以留空 # AbstractUser已经包含了username、email、password等核心字段 class Meta: verbose_name = "User Register" verbose_name_plural = "User Register" # 不需要自己写save方法处理密码加密,AbstractUser会自动完成 def __str__(self): return self.username
必须配置的一步:在项目的settings.py里指定自定义用户模型:
AUTH_USER_MODEL = '你的APP名称.UserRegister' # 替换成你实际的app名字,比如'accounts.UserRegister'
注意:如果是新项目,建议清空数据库后重新执行
makemigrations和migrate;如果是已有数据的项目,需要做数据迁移兼容(新手推荐新项目清空重来)。
2. 修复forms.py
现在模型继承了AbstractUser,表单可以简化,UserCreationForm会自动处理很多基础逻辑:
from django import forms from django.contrib.auth.forms import UserCreationForm from django.core.exceptions import ValidationError from .models import UserRegister class UserRegisterForm(UserCreationForm): username = forms.CharField(max_length=50, required=True, widget=forms.TextInput(attrs={'placeholder': 'Username', 'class': 'input-group'})) email = forms.EmailField(max_length=70, required=True, widget=forms.EmailInput(attrs={'placeholder': 'Email', 'class': 'input-group'})) password1 = forms.CharField(max_length=128, required=True, widget=forms.PasswordInput(attrs={'placeholder': 'Password', 'class': 'input-group', 'id': 'password'})) password2 = forms.CharField(max_length=128, required=True, widget=forms.PasswordInput(attrs={'placeholder': 'Confirm Password', 'class': 'input-group', 'id': 'confirm_password'})) class Meta: model = UserRegister fields = ['username', 'email', 'password1', 'password2'] def clean_email(self): email = self.cleaned_data.get('email') if UserRegister.objects.filter(email=email).exists(): raise ValidationError('This email address is already in use.') return email # 以下两个方法可以删除: # 1. clean_username:AbstractUser已经默认username是唯一的,UserCreationForm会自动验证 # 2. clean:UserCreationForm已经内置了密码一致性验证
小细节:之前你给password1和password2的widget都用了
id="password",会导致DOM元素ID重复,我把确认密码的ID改成了confirm_password,避免前端冲突。
3. 修复views.py
之前手动创建用户的方式不仅麻烦,还可能导致密码重复加密的问题,现在用表单的save()方法更规范:
from django.shortcuts import render from django.http import HttpResponseRedirect ,Http404 from .forms import UserRegisterForm from django.contrib import messages # 保留你的products列表和其他视图函数不变 def Login(request): if request.method == "POST": form = UserRegisterForm(request.POST) if form.is_valid(): # 直接调用form.save(),自动完成用户创建和密码加密 form.save() messages.success(request, 'Your account has been created!') return HttpResponseRedirect('/Products') else: print("Form is not valid") print(form.errors) else: form = UserRegisterForm() return render(request, 'login.html', {'form': form})
之前手动实例化
UserRegister的方式,会导致密码被你的模型save方法再次加密,最终用户登录时密码验证失败,用form.save()就完全避免了这个问题。
4. 修复login.html的小问题
你之前把表单的action设为/Products,其实应该提交到当前的注册视图,然后由视图重定向到Products,所以可以把action留空:
<form method="POST" action=""> {% csrf_token %} <!-- 保留其他表单内容不变 --> </form>
另外按钮文本是Sign In(登录),但这是注册页面,改成Sign Up(注册)会更符合用户预期,这是细节优化~
备注:内容来源于stack exchange,提问作者Hardik Jain

