I get `NoReverseMatch at /accounts/invite-user/` from the url in email template

Hi there,

I am trying to send an email to CLI or Console from Django views.py. I am generating a URL using url tag in email template, but upon parsing the template, before it was working perfectly fine and I was getting email in CLI, but now, I get the below error:

NoReverseMatch at /accounts/invite-user/
Reverse for 'invite_user_confirm' not found. 'invite_user_confirm' is not a valid view function or pattern name.
Request Method:	POST
Request URL:	http://127.0.0.1:8000/accounts/invite-user/
Django Version:	4.0.5
Exception Type:	NoReverseMatch
Exception Value:	
Reverse for 'invite_user_confirm' not found. 'invite_user_confirm' is not a valid view function or pattern name.
Exception Location:	D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\urls\resolvers.py, line 802, in _reverse_with_prefix
Python Executable:	D:\Projects\meistery\venvs\inviteandresetpass\Scripts\python.exe
Python Version:	3.10.4
Python Path:	
['D:\\Projects\\meistery\\projects\\pricing_password_management_poc\\inviteandresetpass',
 'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python310\\python310.zip',
 'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python310\\DLLs',
 'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python310\\lib',
 'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python310',
 'D:\\Projects\\meistery\\venvs\\inviteandresetpass',
 'D:\\Projects\\meistery\\venvs\\inviteandresetpass\\lib\\site-packages']
Server time:	Thu, 23 Jun 2022 16:42:36 +0000
Error during template rendering
In template D:\Projects\meistery\projects\pricing_password_management_poc\inviteandresetpass\apps\accounts\templates\accounts\invite-user-email.txt, error at line 14

Reverse for 'invite_user_confirm' not found. 'invite_user_confirm' is not a valid view function or pattern name.
4	We are pleased to invite you to join PricingMeister.
5	
6	{% if invitation.invitee_first_name != '' and invitation.invitee_last_name != '' %}
7	We have set your first name, last name and email already, you just need to set your own password.
8	{% else %}
9	We have set your email already, you just need to set your own password.
10	{% endif %}
11	
12	Please use the below link to set your password.
13	
14	{{ protocol }}://{{ domain }}{% url 'invite_user_confirm' uidb64=uid token=token %}
15	
16	This link can only be used once. If you need to reset your password again, please visit {{ protocol }}://{{domain}} and request another reset.
17	
18	If you did not make this request, you can simply ignore this email.
19	
20	Sincerely,
21	The Website Team
22	
23	{% endautoescape %}

This is the detailed Traceback

Traceback Switch to copy-and-paste view
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\core\handlers\exception.py, line 55, in inner
                response = get_response(request) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\core\handlers\base.py, line 197, in _get_response
                response = wrapped_callback(request, *callback_args, **callback_kwargs) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\views\generic\base.py, line 84, in view
            return self.dispatch(request, *args, **kwargs) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\views\generic\base.py, line 119, in dispatch
        return handler(request, *args, **kwargs) …
Local vars
D:\Projects\meistery\projects\pricing_password_management_poc\inviteandresetpass\apps\accounts\views.py, line 136, in post
                email = render_to_string(email_template_name, email_details) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\loader.py, line 62, in render_to_string
    return template.render(context, request) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\backends\django.py, line 62, in render
            return self.template.render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 175, in render
                    return self._render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 167, in _render
        return self.nodelist.render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 1000, in render
        return SafeString("".join([node.render_annotated(context) for node in self])) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 1000, in <listcomp>
        return SafeString("".join([node.render_annotated(context) for node in self])) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 958, in render_annotated
            return self.render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\defaulttags.py, line 52, in render
        output = self.nodelist.render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 1000, in render
        return SafeString("".join([node.render_annotated(context) for node in self])) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 1000, in <listcomp>
        return SafeString("".join([node.render_annotated(context) for node in self])) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\base.py, line 958, in render_annotated
            return self.render(context) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\template\defaulttags.py, line 472, in render
            url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\urls\base.py, line 88, in reverse
    return resolver._reverse_with_prefix(view, prefix, *args, **kwargs) …
Local vars
D:\Projects\meistery\venvs\inviteandresetpass\lib\site-packages\django\urls\resolvers.py, line 802, in _reverse_with_prefix
        raise NoReverseMatch(msg) …
Local vars

This is my views.py:

from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.views import View
from django.template.loader import render_to_string
from django.utils.http import urlsafe_base64_encode
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.core.mail import send_mail, BadHeaderError

from .forms import InviteUserForm


class InviteUser(View):
    def get(self, request: HttpRequest) -> HttpResponse:        
        invite_user_form = InviteUserForm()

        context = {
            "title": "Invite Someone for Registration",
            "invite_user_form": invite_user_form
        }

        return render(request, "accounts/invite-user.html", context)

    def post(self, request: HttpRequest) -> HttpResponseRedirect:
        invite_user_form = InviteUserForm(request.POST)

        if invite_user_form.is_valid():
            data = invite_user_form.cleaned_data
            
            if request.user.is_authenticated and request.user.is_superuser:
                subject = "Invitation to Join PricingMeister"
                email_template_name = "accounts/invite-user-email.txt"
                user = request.user
                
                email_details = {
                    "email": str(data["invitee_email"]),
                    'domain': '127.0.0.1:8000',
                    'site_name': 'PricingMeister',
                    "uid": urlsafe_base64_encode(force_bytes(user.pk)),
                    "user": user,
                    'token': default_token_generator.make_token(user),
                    'protocol': 'https',
                }
                
                email = render_to_string(email_template_name, email_details)
                
                try:
                    send_mail(subject, email, 'admin@pricingmeister.com' , [user.email], fail_silently=False)
                except BadHeaderError:
                    return HttpResponse('Invalid header found.')
                
                return redirect("/accounts/invite-user/done/")
            else:
                return HttpResponse('You are not authorized to view this page.')
        else:
            print("Form is not valid")

My invite-user-email.txt email template is:

{% autoescape off %}
Hi,

We are pleased to invite you to join PricingMeister.

{% if invitation.invitee_first_name != '' and invitation.invitee_last_name != '' %}
We have set your first name, last name and email already, you just need to set your own password.
{% else %}
We have set your email already, you just need to set your own password.
{% endif %}

Please use the below link to set your password.

{{ protocol }}://{{ domain }}{% url 'invite_user_confirm' uidb64=uid token=token %}

This link can only be used once. If you need to reset your password again, please visit {{ protocol }}://{{domain}} and request another reset.

If you did not make this request, you can simply ignore this email.

Sincerely,
The Website Team

{% endautoescape %}

My forms.py is

from django import forms

class InviteUserForm(forms.ModelForm):
    invitee_first_name = forms.CharField(max_length=254, label="Invitee First Name", widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Write invitee first name'}))
    invitee_last_name = forms.CharField(max_length=254, label="Invitee Last Name", widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Write invitee last name'}))
    invitee_email = forms.EmailField(max_length=254, required=True, label="Invitee Email", widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Write invitee email'}))
    secret = forms.CharField(max_length=254, required=True, label="Secret", widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Write invitation secret'}))
    message = forms.CharField(label="Message", required=True, widget=forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Write invitation message'}))
    
    class Meta:
        model = Invitation
        fields = ("invitee_first_name", "invitee_last_name", "invitee_email", "secret", "message")

My invite-user.html template is:

<h1>Invite User</h1>

<form method="POST">
    {% csrf_token %}
    {{ invite_user_form }}                    
    <button type="submit">Invite</button>
</form>

My urls.py is:

urlpatterns = [
    path("invite-user/", InviteUser.as_view()),  # Invite User Page
    path("invite-user/<uidb64>/<token>/", InviteUserConfirm.as_view(), name="invite_user_confirm"),  # Invite User Confirm Page
]

Any help will be appreciated.

@KenWhitesell can you help me here?

It looks like you’re missing the url that you’re trying to redirect

Notice, that there is no “/accounts/invite-user/done/” path defined in your urls.py

1 Like