You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django使用UserCreationForm注册提示User类无USERNAME_FIELD属性如何解决

问题根源

你遇到的报错本质是两个基础错误导致的:

  1. 你自定义的User模型直接继承了models.Model,没有遵循Django自定义用户系统的规范,而UserCreationForm依赖Django用户模型自带的USERNAME_FIELD、密码加密等内置属性和方法
  2. 重复定义了用户名字段、视图逻辑错误导致提交表单无响应

解决方案步骤

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 13:36:04