1

I am working on the password reset area of my registration using custom html so am overriding Django's password reset pages.

The reset password initial link works fine and redirects to my custom URL:

/account/reset-password/

There a user can enter their email address and click submit to receive a password reset email. The next page shown should be

/account/reset-password/done/

However when they click submit, I can see from the command line:

POST /account/reset-password/ HTTP/1.1" 302 0
GET /password_reset/done/ HTTP/1.1" 302 0
GET /account/login/ HTTP/1.1" 200 2237

The 2nd line should be going to

/account/reset-password/done/

not

/password_reset/done/

urls.py

app_name='accounts'
from django.conf.urls import url
from . import views
from django.contrib.auth.views import LoginView, LogoutView, PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView, PasswordResetCompleteView
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    url(r'^$', views.home, name='home'),
    url(r'^login/$', LoginView.as_view(template_name='accounts/login.html'), name='login'),
    url(r'^logout/$', LogoutView.as_view(template_name='accounts/logout.html'), name='logout'),
    url(r'^register/$', views.register, name='register'),
    url(r'^profile/$', views.view_profile, name='view_profile'),
    url(r'^profile/edit$', views.edit_profile, name='edit_profile'),
    url(r'^change-password/$', views.change_password, name='change_password'),

    url(r'^reset-password/$',
    PasswordResetView.as_view(template_name='accounts/reset_password.html'),
    {'post_reset_redirect': 'accounts:reset_password_done',
    'email_template_name': 'accounts/reset_password_email.html'},
    name='reset_password'),

    url(r'^reset-password/done/$',
    PasswordResetDoneView.as_view(template_name='accounts/reset_password_done.html'),
    name='reset_password_done'),

    url(r'^reset-password/confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>,+)/$',
    PasswordResetConfirmView.as_view(template_name='accounts/reset_password_confirm.html'),
    name='reset_password_confirm'),

    url(r'^reset-password/complete/$',
    PasswordResetConfirmView.as_view(template_name='accounts/reset_password_complete.html'),
    name='reset_password_complete'),

]

settings.py

INSTALLED_APPS = [
    'accounts',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

middleware.py

import re

from django.conf import settings
from django.urls import reverse
from django.shortcuts import redirect
from django.contrib.auth import logout

EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
    EXEMPT_URLS += [re.compile(url) for url in settings.LOGIN_EXEMPT_URLS]

class LoginRequiredMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        assert hasattr(request, 'user')
        path = request.path_info.lstrip('/')
        url_is_exempt = any(url.match(path) for url in EXEMPT_URLS)

        if path == reverse('accounts:logout').lstrip('/'):
            logout(request)

        if request.user.is_authenticated and url_is_exempt:
            return redirect(settings.LOGIN_REDIRECT_URL)
        elif request.user.is_authenticated or url_is_exempt:
            return None
        if not request.user.is_authenticated and url_is_exempt:
            return None
        else:
            return redirect(settings.LOGIN_URL)
Trilla
  • 943
  • 2
  • 15
  • 31

1 Answers1

5

You can set your success_url in PasswordResetView,

url(r'^reset-password/$',
    PasswordResetView.as_view(template_name='accounts/reset_password.html'),
    {
    'email_template_name': 'accounts/reset_password_email.html',
     'success_url' : reverse_lazy('accounts:reset_password_done')
     },
    name='reset_password'),

or you can directly pass success_url in .as_view()

 url(r'^reset-password/$',
        PasswordResetView.as_view(template_name='accounts/reset_password.html',
         email_template_name = 'accounts/reset_password_email.html',
         success_url = reverse_lazy('accounts:reset_password_done'))  ,
         name='reset_password'),
Pankaj Sharma
  • 2,185
  • 2
  • 24
  • 50
  • You can remove `post_reset_redirect`, it isn’t used by the class based view. I would also move `success_url` inside `.as_view()` so that the arguments are all in one place. – Alasdair Oct 20 '18 at 12:47
  • check your template directory – Pankaj Sharma Oct 20 '18 at 13:31
  • Okay I'm sorry for all the comments added then deleted..everything is working now, thank you very much for your answer. However when the `password-reset/done/` page shows and the email is sent, when I click on the email link to reset the password it redirects again to `account/login` – Trilla Oct 20 '18 at 13:33
  • i have tried email_template_name = 'accounts/reset_password_email.html', success_url = reverse_lazy('accounts:reset_password_done') but still no luck. i tried to edit template_name='accounts/reset_password.html, seems like django is reaching out to this hml file. but when i delete all the code or kept all the code inside reset_password.html, it won't have any effect. seems like whtever i write it isn't rendering to base.html. what should is the effective solution? – ali May 14 '20 at 13:40