Reputation: 2550
I'm using Django forms to change a user's password when they forget it:
#views.py
def change_forgotten_password(request, key):
if request.method == 'GET':
form = ChangePasswordForm()
return render(request, 'freelancestudent/change_forgotten_password.html', {'form': form})
else: # post
form = ChangePasswordForm(request.POST)
if form.is_valid():
user = User.objects.get(forgot_password_key=key)
user.set_password(form.cleaned_data['password'])
user.save()
return redirect('/')
#forms.py
class ChangePasswordForm(forms.Form):
password = forms.CharField(widget=forms.PasswordInput)
confirm_password = forms.CharField(widget=forms.PasswordInput)
def is_valid(self):
if self.cleaned_data['password'] == self.cleaned_data['confirm_password']:
return True
When I step through my code using PyCharm's debugger everything works exactly as I want it to; if the passwords match it updates the selected user's password. However, if I run it as (python manage.py runserver
) it presents the error:
AttributeError at /change-forgotten-password/wemnj8vvk37yvikf/
'ChangePasswordForm' object has no attribute 'cleaned_data'
at the line in forms.py
which reads:
if self.cleaned_data['password'] == self.cleaned_data['confirm_password']:
...
Upvotes: 1
Views: 46
Reputation: 15398
form.cleaned_data
is filled by form.is_valid()
. You forgot to call the super implementation in your form.
def is_valid(self):
return (
super(ChangePasswordForm, self).is_valid()
and self.cleaned_data['password'] == self.cleaned_data['confirm_password']
)
In general, however, I'd discourage overriding is_valid()
and instead override form.clean()
or similiar. As indicated by Brandon, django already does this in its own SetPasswordForm
:
def clean_new_password2(self):
password1 = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('confirm_password')
if password1 and password2:
if password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
password_validation.validate_password(password2, self.user)
return password2
You might go DRY and simply re-use the existing ChangePasswordForm
, which accepts fields 'old_password'
, 'new_password1'
, and 'new_password2'
so you might need to adapt your template.
Upvotes: 1