Resetting password views

Add the following URL patterns for password restoration to the urls.py file of the account application:

# reset password urls
path('password_reset/',
auth_views.PasswordResetView.as_view(),
name='password_reset'),
path('password_reset/done/',
auth_views.PasswordResetDoneView.as_view(),
name='password_reset_done'),
path('reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
path('reset/done/',
auth_views.PasswordResetCompleteView.as_view(),
name='password_reset_complete'),

Add a new file in the templates/registration/ directory of your account application and name it password_reset_form.html. Add the following code to it:

{% extends "base.html" %}

{% block title %}Reset your password{% endblock %}

{% block content %}
<h1>Forgotten your password?</h1>
<p>Enter your e-mail address to obtain a new password.</p>
<form action="." method="post">
{{ form.as_p }}
<p><input type="submit" value="Send e-mail"></p>
{% csrf_token %}
</form>
{% endblock %}

Now, create another file in the same directory and name it password_reset_email.html. Add the following code to it:

Someone asked for password reset for email {{ email }}. Follow the link below: 
{{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}
Your username, in case you've forgotten: {{ user.get_username }}

The password_reset_email.html template will be used to render the email sent to users to reset their password.

Create another file in the same directory and name it password_reset_done.html. Add the following code to it:

{% extends "base.html" %}

{% block title %}Reset your password{% endblock %}

{% block content %}
<h1>Reset your password</h1>
<p>We've emailed you instructions for setting your password.</p>
<p>If you don't receive an email, please make sure you've entered the address you registered with.</p>
{% endblock %}

Create another template in the same directory and name it password_reset_confirm.html. Add the following code to it:

{% extends "base.html" %}

{% block title %}Reset your password{% endblock %}

{% block content %}
<h1>Reset your password</h1>
{% if validlink %}
<p>Please enter your new password twice:</p>
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Change my password" /></p>
</form>
{% else %}
<p>The password reset link was invalid, possibly because it has
already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}

We check whether the provided link is valid. The view PasswordResetConfirmView sets this variable and puts it in the context of the password_reset_confirm.html template. If the link is valid, we display the user password reset form.

Create another template and name it password_reset_complete.html. Enter the following code into it:

{% extends "base.html" %}

{% block title %}Password reset{% endblock %}

{% block content %}
<h1>Password set</h1>
<p>Your password has been set. You can <a href="{% url "login" %}">log in now</a></p>
{% endblock %}

Finally, edit the registration/login.html template of the account application, and add the following code after the <form> element:

<p><a href="{% url "password_reset" %}">Forgotten your 
password?</a></p>

Now, open http://127.0.0.1:8000/account/login/ in your browser and click on the Forgotten your password? link. You should see the following page:

At this point, you need to add an SMTP configuration to the settings.py file of your project so that Django is able to send emails. You learned how to add email settings to your project in Chapter 2, Enhancing Your Blog with Advanced Features. However, during development, you can configure Django to write emails to the standard output instead of sending them through an SMTP server. Django provides an email backend to write emails to the console. Edit the settings.py file of your project, and add the following line:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

The EMAIL_BACKEND setting indicates the class to use to send emails.

Return to your browser, enter the email address of an existing user, and click on the SEND E-MAIL button. You should see the following page:

Take a look at the console where you are running the development server. You will see the generated email, as follows:

Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Password reset on 127.0.0.1:8000
From: webmaster@localhost
To: user@domain.com
Date: Fri, 15 Dec 2017 14:35:08 -0000
Message-ID: <20150924143508.62996.55653@zenx.local>

Someone asked for password reset for email user@domain.com. Follow the link below:
http://127.0.0.1:8000/account/reset/MQ/45f-9c3f30caafd523055fcc/
Your username, in case you've forgotten: zenx

The email is rendered using the password_reset_email.html template we created earlier. The URL to reset your password includes a token that was generated dynamically by Django. Copy the URL and open it in your browser. You should see the following page:

The page to set a new password corresponds to the password_reset_confirm.html template. Fill in a new password and click on the CHANGE MY PASSWORD button. Django creates a new encrypted password and saves it in the database. You will see the following success page:

Now, you can log back into your account using your new password.

Each token to set a new password can be used only once. If you open the link you received again, you will get a message stating that the token is invalid.

You have integrated the views of the Django authentication framework in your project. These views are suitable for most cases. However, you can create your own views if you need a different behavior.

Django also provides the authentication URL patterns we just created. You can comment out the authentication URL patterns we added to the urls.py file of the account application and include django.contrib.auth.urls instead, as follows:

from django.urls import path, include
# ...

urlpatterns = [
# ...
path('', include('django.contrib.auth.urls')),
]

You can see the authentication URL patterns included at https://github.com/django/django/blob/stable/2.0.x/django/contrib/auth/urls.py.