user6922072
user6922072

Reputation:

django : SetPasswordForm is not valid without error

This is my first time to use SetPasswordForm. The form is not valid but does not shows error message. So I'm having hard time to figure out which part went wrong.

urls.py

url(r'^password_change/(?P<username>[-\w.]+)/$', views.password_change, name='password_change'),
url(r'^password_change_done/$', views.password_change_done, name='password_change_done'),

When user input their new password and if the action succeeded, the page will redirect to password_change_done.

views.py

@login_required
def password_change(request, username):
    if request.method == 'POST':
        form = PasswordChangeForm(data=request.POST, user=request.user)
        if form.is_valid():            
            oldpassword = form.cleaned_data.get('oldpassword')
            password1 = form.cleaned_data.get('password1')
            password2 = form.cleaned_data.get('password2')
            if password1 == password2:
                update_session_auth_hash(request, form.username)
                form.save()
                return HttpResponseRedirect('/blog/password_change_done/') 
            else:
                return render(request, 'blog/profile.html', {'error_message': 'password mismatch'})
        else:
        return render(request, 'blog/profile.html', {'error_messages': form.errors })
    else:
        return redirect(reverse('blog:profile', args=[form.user.get_username()]))


@login_required
def password_change_done(request):
return render(request, 'blog/password_change_done.html')

forms.py

class PasswordChangeForm(SetPasswordForm):
    error_messages = dict(SetPasswordForm.error_messages, **{
    'password_incorrect': ("Your old password was entered incorrectly. Please enter it again."),
    })
    oldpassword = forms.CharField(
        label=("Old password"),
        strip=False,
        widget=forms.PasswordInput(attrs={'autofocus': True}),
    )
    field_order = ['oldpassword', 'password1', 'password2']
    def __init__(self, user, data, **kwargs):
        self.user = user
        super(PasswordChangeForm, self).__init__(data, **kwargs)
    def clean_oldpassword(self):
        oldpassword = self.cleaned_data["oldpassword"]
        if not self.user.check_password(oldpassword):
            raise forms.ValidationError(
                self.error_messages['password_incorrect'],
                code='password_incorrect',
            )
        return oldpassword

templates.py

{{ form.errors }}
{{ form.non_field_errors }}
{% if error_message %}
    <h2><strong>{{ error_message }}</strong></h2>
{% else %}<br>
{% endif %}
<form class="form-horizontal" role="form" action="{% url 'blog:password_change' user.username %}" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit" class="button-primary">submit</button></div>
</form>

I put {{ form.errors }} and {{ form.non_field_errors }} so if error happens than it can display error message on website. However till now no message displayed and seems like nothing happens whenever user click submit button.

Upvotes: 0

Views: 1652

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599630

You have quite a few issues here, but the main problem - as I have told you before - is how you are passing things to the template. You need to follow the pattern as shown in the documentation, and you need to be consistent about your variable naming.

Firstly, move your password check to the form itself:

class PasswordChangeForm(SetPasswordForm):
    ...
    def clean(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 1= password2:
            raise forms.ValidationError('password mismatch')

Now, fix your view:

def password_change(request, username):
    if request.method == 'POST':
        form = PasswordChangeForm(data=request.POST, user=request.user)
        if form.is_valid():
            update_session_auth_hash(request, form.username)
            form.save()
            return HttpResponseRedirect('/blog/password_change_done/') 
        else:
            return render(request, 'blog/profile.html', {'form': form })
    else:
        return redirect(reverse('blog:profile', args=[username]))

And finally, remove {{ error_messages }} from your template.

Upvotes: 2

Related Questions