Django password_change() View

Django provides us the following two views which helps us to change passwords.

View Function Description
password_change() It displays a password change form, which allows user to change their password by retyping existing password.
password_change_done() It displays a success message when a user successfully updates the password.

Both of these views are password protected using login_required decorator. So, if you try to access these views without logging in, Django will redirect you to URL specified in LOGIN_URL, which in our case happens to be http://127.0.0.1:2000/cadmin/login/. If we had not set LOGIN_URL to 'login' then login_required would have redirected us to default login URL which is /accounts/login/. We can verify this by adding the following URL pattern at the beginning of the urlpatterns list in cadmin's urls.py.

TGDB/django_project/cadmin/urls.py

...
urlpatterns = [
    url(r'^password-change/$', auth_views.password_change , name='password_change'),
    ...
]

If you are already logged in, logout first before proceeding. Then, visit http://127.0.0.1:8000/cadmin/password-change/, you will be redirected to http://127.0.0.1:2000/cadmin/login/?next=/cadmin/password-change/.

password_change-view-is-protected.png

Notice that the redirected URL contains next query parameter whose value is /cadmin/password-change/. It means that after successful login the built-in login() view will redirect the user to /cadmin/password-change/.

The password_change() view works in conjunction with password_change_done() view. The job of the password_change_done() view is to display success message when user successfully updates password. The password_change() view accepts an additional argument named post_change_redirect. The post_change_redirect points to the URL to redirect after successful password change. Generally, it points to the URL pattern which calls password_change_done() view.

Open cadmin's urls.py and add another URL pattern named password_change_done and update password_change URL pattern as follows:

TGDB/django_project/cadmin/urls.py

...
urlpatterns = [
    url(r'^password-change-done/$',
        auth_views.password_change_done,
        name='password_change_done'
    ),
    url(r'^password-change/$',
        auth_views.password_change,
        {'post_change_redirect': 'password_change_done'},
        name='password_change'
    ),

    ...
]

To view the fruits of our labor visit http://127.0.0.1:8000/cadmin/password-change/. If you are not already logged in, login now and you will be presented with password change page, which looks like this:

password_change-page.png

To change password, enter old password first then your new password twice and hit "CHANGE MY PASSWORD" button at the bottom of the screen. On success you will be redirect to http://127.0.0.1:8000/cadmin/password-change-done/, which looks like this:

password_change_done-page.png

By default, password_change() and password_change_done() uses password_change_form.html and password_change_done.html templates respectively from Django Admin app. We can override this behavior by using template_name keyword argument as usual.

Update password_change and password_change_done URL patterns as follows:

TGDB/django_project/cadmin/urls.py

...
urlpatterns = [
    url(r'^password-change-done/$',
        auth_views.password_change_done,
        {'template_name': 'cadmin/password_change_done.html'},
        name='password_change_done'
    ),
    url(r'^password-change/$',
        auth_views.password_change,
        {'template_name': 'cadmin/password_change.html' , 'post_change_redirect': 'password_change_done'},
        name='password_change'
    ),
    ...
]

Create two new templates password_change.html and password_change_done.html in the cadmin app with the following code.

TGDB/django_project/cadmin/templates/cadmin/password_change.html

{% extends "cadmin/base_admin.html" %}

{% block title %}
    Password Change - {{ block.super }}
{% endblock %}

{% block main %}

    <div class="main">

            <p>&#187; <a href="{% url 'password_change' %}">Change Password</a> </p>

            <h3>Change Password</h3>

            <form action="{% url 'password_change' %}" method="post">
                {% csrf_token %}
                <table>
                    {{ form.as_table }}
                    <tr>
                        <td></td>
                        <td><input type="submit" value="Submit"></td>
                    </tr>
                </table>
            </form>
    </div>

{% endblock %}

TGDB/django_project/cadmin/templates/cadmin/password_change_done.html

{% extends "cadmin/base_admin.html" %}

{% block title %}
    Password Change - {{ block.super }}
{% endblock %}

{% block main %}

    <div class="main">

            <p>Password Changed</p>
    </div>

{% endblock %}

Visit the http://127.0.0.1:8000/cadmin/password-change/ and you should see our custom password change template instead of the default one.

custom-password-change-template.png

Update the password of the logged in user and on success you will get a page like this:

custom-password-change-done-template.png