pythondjangodjango-rest-frameworkdjango-templatespassword-recovery

DRF password rest workflow throwing django.template.exceptions.TemplateDoesNotExist


I'm using Django Rest Password Reset for the reset password workflow as it's, at my sight, the best supported for this particular case.

In urls.py

# Password reset
path('reset-password/verify-token/', views.CustomPasswordTokenVerificationView.as_view(), name='password_reset_verify_token'),
path('reset-password/', include('django_rest_passwordreset.urls', namespace='password_reset')),

and in settings.py

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

If i go to reset-password/ after running the server, this is what i get

Django REST Reset Password Request Token

If i POST an email that's not stored in the DB, then it gives a HTTP 400 Bad Request with

{
    "email": [
        "There is no active user associated with this e-mail address or the password can not be changed"
    ]
}

If i POST an email that's stored in the DB, then I get

django.template.exceptions.TemplateDoesNotExist: user_reset_password.html

TemplateDoesNotExist at /test_app/reset-password/ user_reset_password.html

I placed the signal receiver inside of a view named CustomPasswordResetView

class CustomPasswordResetView:
    @receiver(reset_password_token_created)
    def password_reset_token_created(sender, reset_password_token, *args, **kwargs):
        """
          Handles password reset tokens
          When a token is created, an e-mail needs to be sent to the user
        """
        # send an e-mail to the user
        context = {
            'current_user': reset_password_token.user,
            'username': reset_password_token.user.username,
            'email': reset_password_token.user.email,
            'reset_password_url': "{}?token={}".format(reverse('password_reset:reset-password-request'), reset_password_token.key)
        }

        # render email text
        email_html_message = render_to_string('user_reset_password.html', context)
        email_plaintext_message = render_to_string('user_reset_password.txt', context)

        msg = EmailMultiAlternatives(
            # title:
            "Password Reset for {title}".format(title="Some website title"),
            # message:
            email_plaintext_message,
            # from:
            "test@test.com",
            # to:
            [reset_password_token.user.email]
        )
        msg.attach_alternative(email_html_message, "text/html")
        msg.send()

As you can read in it, there's a place for the render email text with

email_html_message = render_to_string('user_reset_password.html', context)
email_plaintext_message = render_to_string('user_reset_password.txt', context)

Within the same folder where the view is at, created two files user_reset_password.html and user_reset_password.txt with the same content in them

{% load i18n %}{% blocktrans %}Hello!

You're receiving this e-mail because you or someone else has requested a password for your user account.
It can be safely ignored if you did not request a password reset. Click the link below to get the token.{% endblocktrans %}

{{ reset_password_url }}

Then, if you go to /test_app/reset-password/confirm/, you can paste the token and the new password.

{% if email %}{% blocktrans %}In case you forgot, your email is {{ email }}.{% endblocktrans %}

{% endif %}{% blocktrans %}Have a great day!
{% endblocktrans %}

Why do i still TemplateDoesNotExist at /test_app/reset-password/ user_reset_password.html and how to solve it?


Solution

  • As from templates documentation

    Templates engines are configured with the TEMPLATES setting. It’s a list of configurations, one for each engine. The default value is empty.

    You can have root template folder in which you should add templates

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            ...
        },
    

    If you want to have per app templates folder you can check following docs

    'APP_DIRS': True,