I'm getting a KeyError for 'password' when I try to submit my form.
trace:
Request Method: POST
Request URL: http://localhost:8000/register/
Django Version: 1.2.1
Python Version: 2.7.0
Installed Applications:
['django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'djangoproject1.authentication']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware')
Traceback:
File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
100. response = callback(request, *callback_args, **callback_kwargs)
File "C:\Users\jec23\My Java Projects\djangoproject1\src\djangoproject1\authentication\views.py" in register
20. if rf.is_valid() and pf.is_valid():
File "C:\Python27\lib\site-packages\django\forms\forms.py" in is_valid
121. return self.is_bound and not bool(self.errors)
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _get_errors
112. self.full_clean()
File "C:\Python27\lib\site-packages\django\forms\forms.py" in full_clean
268. self._clean_form()
File "C:\Python27\lib\site-packages\django\forms\forms.py" in _clean_form
296. self.cleaned_data = self.clean()
File "C:\Users\jec23\My Java Projects\djangoproject1\src\djangoproject1\authentication\forms.py" in clean
16. if self.cleaned_data['cpassword']!=self.cleaned_data['password']:
Exception Type: KeyError at /register/
Exception Value: 'password'
views:
def register(request):
if request.method == 'POST':
rf = forms.RegisterForm(request.POST)
pf = forms.ProfileForm(request.POST)
if rf.is_valid() and pf.is_valid():
newuser = User(username=rf.cleaned_data['username'],email=rf.cleaned_data['email'])
newuser.set_password(rf.cleaned_data['password'])
newuser.save()
profile = pf.save(commit=False)
profile.user = newuser
profile.save()
return HttpResponseRedirect("/register-success/")
else:
return render_to_response("authentication/index.html", {'form1': rf, 'form2':pf})
else:
return main(request)
forms:
class RegisterForm(forms.Form):
username = forms.CharField(min_length=6,max_length=15)
password = forms.CharField(min_length=6,max_length=15,widget = forms.PasswordInput())
cpassword = forms.CharField(label='Confirm Password',widget = forms.PasswordInput())
email = forms.EmailField(label='E-mail Address')
def clean(self):
if self.cleaned_data['cpassword']!=self.cleaned_data['password']:
raise forms.ValidationError("Passwords don't match")
return self.cleaned_data
class ProfileForm(forms.ModelForm):
phonenumber = forms.CharField(label='Phone Number')
class Meta:
model = UserProfile
exclude = ('user')
From my own experience, I found that if you want to do some validation in multiple fields, even if they are marked as required=True, when you override the clean()
method in your form, if the fields you want to validate are not filled when submitting it and you try to acess them as cleaned_data["field_name"]
your code will explode with a KeyError
. To avoid this, just access the field in cleaned_data through the get()
dictionary method and check if is None, or pass a default value. As a corollary:
my_field = cleaned_data.get("field_name") # This is safe and it will work! :)
my_filed = cleaned_data["field_name"] # This will crash when the field was not filled! :(
I hope this helps someone else, I lost a great amount of time because of this silly thing!
Aha! The validation error message that you are seeing is actually not a validation error message. Let me explain. When you render the model form instance using as_p
, it renders each field in the following way:
<p><label ...>fieldname</label> <input ... name="fieldname" /> HELP TEXT IF ANY</p>
The string Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters
that you are seeing to the right hand side of the field is nothing but the help text. This help text is taken from the model definition - you can verify this by visiting django/contrib/auth/models.py
and inspecting the definition of User
class.
When you override the username
field you are omitting any help text. Naturally the "error" disappears.
In order to verify this theory do the following in your main
method.
def main(request):
uf = forms.UserForm()
upf = forms.UserProfileForm()
print "User form is bound:%s errors:%s" % (uf.is_bound, uf.errors)
return render_to_response("authentication/index.html", {'form1': uf, 'form2':upf})
Update
if self.cleaned_data['cpassword']!=self.cleaned_data['password']:
This line can cause trouble when the user doesn't supply one or both of password
and cpassword
. For example, try this from the Django shell:
>>> data = dict(username = 'admin', cpassword = 'foo', email='[email protected]')
>>> f = RegisterForm(data)
>>> f.is_bound
True
>>> f.is_valid()
Traceback (most recent call last):
...
File "<pyshell#2>", line 8, in clean
if self.cleaned_data['cpassword']!=self.cleaned_data['password']:
KeyError: 'password'
Change your form's clean
method to make sure that both values are present before comparing. Something like this:
def clean(self):
password = self.cleaned_data.get('password', None)
cpassword = self.cleaned_data.get('cpassword', None)
if password and cpassword and (password == cpassword):
return self.cleaned_data
else:
raise forms.ValidationError("Passwords don't match")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With