16. Django 1.8 Server Build - CentOS 7 hosted on VPS - User Authentication 3 (password reset)
In this tutorial, we want to allow a user to reset their password by generating a one-time use link that can be used to reset the password, and sending that link to the user's registered email address.
Using the Django authentication system
Actually, code (driver/templates/login.html) was there even though it's not fully implemented:
{% extends "base.html" %} {% block content %} <form action="" method="post"> {% csrf_token %} {% if form.errors %}<p>Please correct the following fields:</p>{% endif %} <div class="register_div"> {% if form.username.errors %}<p class="error">{{ form.username.errors }}</p>{% endif %} <p><label for="username"{% if form.username.errors %} class="error"{% endif %}>Username:</label></p> <p>{{ form.username }}</p> </div> <div class="register_div"> {% if form.password.errors %}<p class="error">{{ form.password.errors }}</p>{% endif %} <p><label for="password"{% if form.password.errors %} class="error"{% endif %}>Password:</label></p> <p>{{ form.password }}</p> </div> <p><input type="submit" alt="register" /></p> </form> <p>Forgot your password? <a href="/resetpassword/">Reset it!</a></p> {% endblock %}
We want to switch the base_site.html to base.html to customize the pages for other html pages as well.
This is our current file structure:
We'll add the following highlighted four urls to urls.py:
from django.conf.urls import include, url from django.contrib import admin from django.conf import settings urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^tinymce/', include('tinymce.urls')), url(r'^$', 'pages.views.MainHomePage'), url(r'^cars/$', 'car.views.CarsAll'), url(r'^cars/(?P<carslug>.*)/$', 'car.views.SpecificCar'), url(r'^makes/(?P<makeslug>.*)/$', 'car.views.SpecificMake'), url(r'^media/(?P<path>.*)$', 'django.views.static.serve', { 'document_root': settings.MEDIA_ROOT, }), url(r'^register/$', 'driver.views.DriverRegistration'), url(r'^login/$', 'driver.views.LoginRequest'), url(r'^logout/$', 'driver.views.LogoutRequest'), url(r'^resetpassword/passwordsent/$', 'django.contrib.auth.views.password_reset_done'), url(r'^resetpassword/$', 'django.contrib.auth.views.password_reset', {'post_reset_redirect' : 'django.contrib.auth.views.password_reset_done'}, name="password_reset"), url(r'^reset/(?P<uidb64>[0-9A-Za-z]+)/(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'), url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete'), ]
We want to copy Django's template files for password reset to our templates. First, we need to find where our Django has been installed.
$ python Python 2.7.5 (default, Jun 24 2015, 00:41:19) [GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import django >>> django
Let's go to /usr/lib64/python2.7/site-packages/django/contrib/admin/templates/registration/:
$ pwd /usr/lib64/python2.7/site-packages/django/contrib/admin/templates/registration $ ls logged_out.html password_reset_complete.html password_reset_email.html password_change_done.html password_reset_confirm.html password_reset_form.html password_change_form.html password_reset_done.html
Now we can copy the registration folder to templates root directory:
$ pwd /srv/www/django/djangotest/driver/templates $ cp -r /usr/lib64/python2.7/site-packages/django/contrib/admin/templates/registration .
Now we have registration folder under driver/templates
$ ls login.html register.html registration $ cd registration $ ls logged_out.html password_reset_complete.html password_reset_email.html password_change_done.html password_reset_confirm.html password_reset_form.html password_change_form.html password_reset_done.html $ rm logged_out.html $ ls password_change_done.html password_reset_confirm.html password_reset_form.html password_change_form.html password_reset_done.html password_reset_complete.html password_reset_email.html
{% extends "base.html" %} {% load i18n %} {% block breadcrumbs %} <div class="breadcrumbs"> <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> › {% trans 'Password reset' %} </div> {% endblock %} {% block title %}{{ title }}{% endblock %} {% block content_title %}<h1>{{ title }}</h1>{% endblock %} {% block content %} <p>{% trans "Forgotten your password?? Enter your email address below, and we'll email instructions for setting a new one." %}</p> <form action="" method="post">{% csrf_token %} {{ form.email.errors }} <p><label for="id_email">{% trans 'Email address:' %}</label> {{ form.email }} <input type="submit" value="{% trans 'Reset my password' %}" /></p> </form> {% endblock %}
Django's template finders let us override any template. Though we placed the admin templates under driver we want to override, the order matters. So, it should look like this:
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'car', 'tinymce', 'pages', 'driver', 'django.contrib.admin', )
Click the "Reset it!" link on Login page, and type in our email:
When we click "Reset my password" with an email, we may got the following "Connection refused" error:
We need to add the following lines in settings.py to setup mail host:
EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST_USER = 'kihyuck.hong@gmail.com' EMAIL_HOST_PASSWORD = 'password' EMAIL_PORT = 587 EMAIL_USE_TLS = True
Once the settings.py is modified, we can click "Reset my password" button. Then, the email will be sent from the EMAIL_HOST with EMAIL_HOST_USER as a sender:
We can see the email in our Inbox:
If we click the link of the email received, we get a page for the New email password setting:
Click "Change my password":
Here is the files we've created so far:
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization