Django使用UserCreationForm注册提示User类无USERNAME_FIELD属性如何解决
问题根源
你遇到的报错本质是两个基础错误导致的:
- 你自定义的
User模型直接继承了models.Model,没有遵循Django自定义用户系统的规范,而UserCreationForm依赖Django用户模型自带的USERNAME_FIELD、密码加密等内置属性和方法 - 重复定义了用户名字段、视图逻辑错误导致提交表单无响应
解决方案步骤
1. 修正自定义用户模型(members/models.py)
不要直接继承models.Model,改为继承Django提供的AbstractUser,它已经内置了username、password、is_active等常用字段,不需要你重复声明,同时会自动满足UserCreationForm的依赖要求:
from django.contrib.auth.models import AbstractUser class User(AbstractUser): # 如果你有额外的自定义字段可以在这里加,比如手机号、昵称等,不需要重复写username和password pass
然后在项目的settings.py中添加配置,告诉Django使用你自定义的用户模型:
AUTH_USER_MODEL = 'members.User'
注意:如果之前已经执行过迁移,需要删除
migrations目录下除了__init__.py之外的文件,同时删除数据库后重新执行python manage.py makemigrations和python manage.py migrate,否则会出现字段冲突报错。
2. 修正注册表单(members/forms.py)
方案A:保留UserCreationForm(推荐,自带密码校验、加密逻辑)
UserCreationForm默认会提供password1(输入密码)和password2(确认密码)两个字段,不需要你手动声明password字段,调整表单配置如下:
from django.contrib.auth.forms import UserCreationForm from django import forms from .models import User class RegisterForm(UserCreationForm): class Meta: model = User fields = ['username'] widgets = { 'username': forms.TextInput(attrs={ 'class': 'form-control', 'data-val': 'true', 'data-val-required': 'Please enter your user name'}), } # 自定义密码字段的属性 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['password1'].widget.attrs.update({'class': 'form-control', 'data-val': 'true', 'data-val-required': 'Please enter your password'}) self.fields['password2'].widget.attrs.update({'class': 'form-control', 'data-val': 'true', 'data-val-required': 'Please confirm your password'})
方案B:改用ModelForm(适合不需要确认密码的简单场景)
如果你不需要确认密码功能,也可以直接使用ModelForm,手动处理密码加密,避免UserCreationForm的多余逻辑:
from django import forms from django.contrib.auth.hashers import make_password from .models import User class RegisterForm(forms.ModelForm): class Meta: model = User fields = ['username', 'password'] widgets = { 'username': forms.TextInput(attrs={ 'class': 'form-control', 'data-val': 'true', 'data-val-required': 'Please enter your user name'}), 'password': forms.PasswordInput(attrs={ 'class': 'form-control', 'data-val': 'true', 'data-val-required': 'Please enter your password' }), } def save(self, commit=True): user = super().save(commit=False) # 手动加密密码,否则密码会明文存储,导致登录验证失败 user.password = make_password(self.cleaned_data['password']) if commit: user.save() return user
3. 修正视图逻辑(members/views.py)
你原来的代码中,POST请求处理结束后,无论验证是否通过都重新实例化了表单,会冲掉表单的错误信息,导致用户看不到报错:
def register(request): if request.method == "POST": form = RegisterForm(request.POST) if form.is_valid(): form.save() return HttpResponseRedirect('login') else: # 只有GET请求的时候才实例化空表单 form = RegisterForm() return render (request, "registration/register.html", context={"form": form})
4. 修正注册模板(templates/registration/register.html)
如果使用方案A的UserCreationForm,需要添加确认密码的输入框,同时展示表单错误信息方便排查问题:
<form method="POST" action="/register/"> {% csrf_token %} <!-- 展示表单全局错误 --> {% if form.errors %} <div class="alert alert-danger"> {% for field, errors in form.errors.items %} {% for error in errors %} <p>{{ error }}</p> {% endfor %} {% endfor %} </div> {% endif %} <div class="form-group"> <label for="username">Username</label> <input type="text" class="form-control" name="username" id="username" value="{{ form.username.value|default:'' }}"/> </div> <div class="form-group"> <label for="password1">Password</label> <input type="password" class="form-control" name="password1" id="password1"/> </div> <div class="form-group"> <label for="password2">Confirm Password</label> <input type="password" class="form-control" name="password2" id="password2"/> </div> <button type="submit" class="btn btn-primary btn-flat m-b-30 m-t-30">Register</button> </form>
如果使用方案B的ModelForm版本,保留你原来的单个password输入框即可。
内容的提问来源于stack exchange,提问作者William Le
相关产品推荐
相关产品推荐

