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

Question:

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.

Asked By: A_K

||

Answers:

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.

Answered By: Sunderam Dubey