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

Django注册表单提交时出现KeyError: 'confirm_password'错误

Django注册表单KeyError: 'confirm_password'问题解决

提交包含用户名、邮箱、密码及确认密码的注册表单时,触发KeyError at /pokedex/register/ "confirm_password"错误——POST数据中存在该字段值,但在RegisterUser表单的clean_password方法中无法从self.cleaned_data获取confirm_password。

相关代码文件

forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta:
        model = CustomUser
        fields = ("email", "password")

class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = ("email", "password")

class RegisterUser(forms.Form):
    username = forms.CharField(max_length=64, required=True)
    email = forms.EmailField()
    password = forms.CharField(max_length=128, widget=forms.PasswordInput(), required=True)
    confirm_password = forms.CharField(max_length=128, widget=forms.PasswordInput(), required=True)

    def clean_username(self):
        username = self.cleaned_data["username"]
        if CustomUser.objects.filter(username=username).exists():
            raise forms.ValidationError("Email already exists")
        return username
    
    def clean_email(self):
        email = self.cleaned_data['email']
        if CustomUser.objects.filter(email=email).exists():
            raise forms.ValidationError("Email already exists")
        return email

    def clean_password(self):
        password = self.cleaned_data['password']
        confirm_password = self.cleaned_data['confirm_password']
        if password != confirm_password:
            raise forms.ValidationError("Passwords do not match")
        return password

views.py(register_view函数)

def register_view (request):
    if request.method == "POST":
        form = RegisterUser(request.POST)
        if form.is_valid():
            new_user = form.save()
            login(request, new_user)
            return redirect('home')
    else:
        form = RegisterUser()
    return render(request, 'pokedex/register.html', {'form': form})

register.html

{% extends 'pokedex/layout.html' %}

{% block title %}Register{% endblock title %}


{% block body %}

<h1>Register</h1>

{% if form.errors %}
<div class="alert alert-danger">
    <ul>
        {% for error in form.errors.values %}
            <li>{{ error }}</li>
        {% endfor %}
    </ul>
</div>
{% endif %}

<form action="{% url 'register' %}" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Register">
</form>

{% endblock body %}

错误回溯

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/pokedex/register/

Django Version: 4.1.7
Python Version: 3.9.2
Installed Applications:
['pokedex',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\core\handlers\exception.py", line 56, in inner
    response = get_response(request)
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Alice\Documents\Code\stepchallenge\pokedex\views.py", line 45, in register_view
    if form.is_valid():
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\forms\forms.py", line 205, in is_valid
    return self.is_bound and not self.errors
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\forms\forms.py", line 200, in errors
    self.full_clean()
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\forms\forms.py", line 437, in full_clean
    self._clean_fields()
  File "C:\Users\Alice\Documents\Code\env\lib\site-packages\django\forms\forms.py", line 452, in _clean_fields
    value = getattr(self, "clean_%s" % name)()
  File "C:\Users\Alice\Documents\Code\stepchallenge\pokedex\forms.py", line 38, in clean_password
    confirm_password = self.cleaned_data['confirm_password']

Exception Type: KeyError at /pokedex/register/
Exception Value: 'confirm_password'

问题原因

Django表单的字段级clean_<fieldname>方法按字段在表单中定义的顺序依次执行。confirm_password字段定义在password之后,执行clean_password时,confirm_password尚未完成清理流程,因此不会出现在self.cleaned_data中,触发KeyError。

解决方案

跨字段验证(如密码与确认密码匹配)应使用表单的全局clean()方法,该方法在所有字段级clean方法执行完成后调用,此时所有字段的清理值已存入cleaned_data。

修改RegisterUser表单,移除clean_password方法,添加全局clean()方法,同时补充save()方法以支持用户创建:

class RegisterUser(forms.Form):
    username = forms.CharField(max_length=64, required=True)
    email = forms.EmailField()
    password = forms.CharField(max_length=128, widget=forms.PasswordInput(), required=True)
    confirm_password = forms.CharField(max_length=128, widget=forms.PasswordInput(), required=True)

    def clean_username(self):
        username = self.cleaned_data["username"]
        if CustomUser.objects.filter(username=username).exists():
            raise forms.ValidationError("Username already exists")  # 修正原错误提示的混淆问题
        return username
    
    def clean_email(self):
        email = self.cleaned_data['email']
        if CustomUser.objects.filter(email=email).exists():
            raise forms.ValidationError("Email already exists")
        return email

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        confirm_password = cleaned_data.get('confirm_password')

        if password and confirm_password and password != confirm_password:
            self.add_error('confirm_password', "Passwords do not match")  # 将错误关联到对应字段
        return cleaned_data
    
    def save(self, commit=True):
        # 实现用户创建逻辑
        user = CustomUser.objects.create_user(
            username=self.cleaned_data['username'],
            email=self.cleaned_data['email'],
            password=self.cleaned_data['password']
        )
        if commit:
            user.save()
        return user

内容的提问来源于stack exchange,提问作者rolyjin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:17:55