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
相关产品推荐
相关产品推荐

