Search code examples
pythondjangodjango-rest-frameworkdjango-urlsdjango-rest-auth

Django Rest Framework Password Rest Confirm Email not showing Form and returning as none


In my Django Rest Framework, the users request to reset the password and when the email is received and the link is clicked, the url password-reset-confirm/<uidb64>/<token>/ as comes up requested but the form is not showing and when I added it as {{ form }} is displayed NONE

The password reset process is working perfectly fine when I do everytihng on the Django but if I try to reset the password from Django Rest Framework the form does not appear.

Here is the main urls.py

urlpatterns = [
    path('', include('django.contrib.auth.urls')),
    path('password-reset/', auth_views.PasswordResetView.as_view(template_name='users/password_reset.html', success_url=reverse_lazy('password_reset_done')), name='password_reset'),
    path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'), name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/',auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),name='password_reset_confirm',),
    path('password-reset-complete/', auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'), name='password_reset_complete'),
    path('admin/', admin.site.urls),
    path('api/', include('api.urls'), ),
    path('users/', include('users.urls'), ),
]

Here is the API app urls.py that is related to DRF

app_name = 'api'

router = routers.DefaultRouter()
router.register(r'users', UserViewSet, basename='user')

urlpatterns = [
    path('', include(router.urls)),
    path('dj-rest-auth/', include('dj_rest_auth.urls')),
    path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
    path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

here is the template password_reset_confirm.html

<main class="mt-5" >
            <div class="container dark-grey-text mt-5">
                <div class="content-section">
                    <form method="POST">
                        {% csrf_token %}
                        <fieldset class="form-group">
                            <legend class="border-bottom mb-4">Reset Password</legend>
                            {{ form|crispy }}
                            {{ form }}

                        </fieldset>
                        <div class="form-group">
                            <button class="btn btn-outline-info" type="submit">Reset Password</button>
                        </div>
                    </form>
                </div>
            </div>
        </main>

My question is: Why is the form showing as NONE and how do I fix it.


Solution

  • Most probably the form is not going to password_reset_confirm.html since does not include the form in the context of the PasswordResetConfirmView by default.

    Currently, the thing you can do is to create a custom PasswordResetConfirmView by inheriting it in a sub class and pass the form to the template context, using form_class attribute so:

    from django.contrib.auth.forms import SetPasswordForm
    from django.contrib.auth.views import PasswordResetConfirmView
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_protect
    from django.views.decorators.debug import sensitive_post_parameters
    
    
    class CustomPasswordResetConfirmView(PasswordResetConfirmView):
        form_class = SetPasswordForm
        success_url = reverse_lazy('password_reset_complete')
        template_name = 'users/password_reset_confirm.html'
    
        @method_decorator(sensitive_post_parameters('new_password1', 'new_password2'))
        @method_decorator(csrf_protect)
        def dispatch(self, *args, **kwargs):
            return super().dispatch(*args, **kwargs)
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['form'] = self.form_class(user=self.request.user)
            return context
    

    Then in urls.py:

    urlpatterns = [
        # .......
        path('password-reset-confirm/<uidb64>/<token>/', CustomPasswordResetConfirmView.as_view(), name='password_reset_confirm'),
        # .......
    ]
    

    You can provide any success_url according to your need.