I'm trying to use an HTML template for django mail module. MY current issue is that I'm getting this error:
django.template.exceptions.TemplateDoesNotExist
when I try to render HTML inside my app called users
:
html = render_to_string('email/email_confirm.html', context)
Here is my folder layout, my app is called users, my project settings live in /core
. My templates are located in BASE_DIR.
Here is my templates code in settings:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
},
},
]
How can I get Django to properly find the templates folder? I have all my apps hooked up and data is working fine. This is strictly a templates path issue.
EDIT:
I have kept my APP_DIRS
= True and moved the templates/email folder inside the users application folder.
Still django is not finding the template?
Here is the View.py in question:
class CustomUserCreate(APIView):
permission_classes = [AllowAny]
def post(self, request, format='json'):
serializer = CustomUserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
# GENERATE EMAIL CONFIRMATION TOKEN
user_data = serializer.data
user = User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
# GENERATE EMAIL CONFIRMATION TEMPLATE
current_site = get_current_site(request).domain
relative_link = reverse('users:email-verify')
# CHANGE TO HTTPS in PRODUCTION
absurl = 'http://'+current_site+relative_link+"?token="+str(token)
email_body = 'Hi '+ user.username+', Please use link below to verify your email \n' + absurl
context = {
'name': user.first_name,
}
html = render_to_string('email/email_confirm.html', context)
text = render_to_string(email_body, context)
data = {'to_email':user.email,
'email_subject': 'Verify your email',
'email_body':email_body,
'message':text,
'html_message':html
}
Util.send_email(data)
return Response(user_data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
EDIT 2: First I tried doing this:
template = get_template('email/email_confirm.html', { 'name': user.first_name})
I got TypeError: unhashable type: 'dict'
as an error for the above.
Then I switched it around doing this:
absurl = 'http://'+current_site+relative_link+"?token="+str(token)
email_body = 'Hi '+ user.username+', Please use link below to verify your email \n' + absurl
context = {
'name': user.first_name,
}
template = get_template('email/email_confirm.html')
email = render_to_string(template, context)
data = {'to_email':user.email,
'email_subject': 'Verify your email',
'email_body':email_body,
'html_message':email
}
Util.send_email(data)
Which lead to this error:
raise TypeError(f'{funcname}() argument must be str, bytes, or '
TypeError: join() argument must be str, bytes, or os.PathLike object, not 'Template'
final edit:
data = {'to_email':user.email,
'email_subject': 'Please Verify Your Email',
'email_body':email_body,
'html_message':html
}
To configure the Django template system, go to the settings.py file and update the DIRS to the path of the templates folder. Generally, the templates folder is created and kept in the sample directory where manage.py lives. This templates folder contains all the templates you will create in different Django Apps.
Django TemplateDoesNotExist error means simply that the framework can't find the template file. To use the template-loading API, you'll need to tell the framework where you store your templates. The place to do this is in your settings file ( settings.py ) by TEMPLATE_DIRS setting.
extends tag is used for inheritance of templates in django. One needs to repeat the same code again and again. Using extends we can inherit templates as well as variables.
{% %} and {{ }} are part of Django templating language. They are used to pass the variables from views to template. {% %} is basically used when you have an expression and are called tags while {{ }} is used to simply access the variable.
Note that the arguments to render_to_string
are a path to a template, and a context dictionary. Fundamentally the issue is ensuring you are passing a template path to render_to_string
every time you call it.
In your first post, the issue is not with the line that you've highlighted
(html = render_to_string('email/email_confirm.html', context)
), that line is actually totally fine and not the source of your errors. Rather the following line where the first argument to render_to_string
is a string of the email body: text = render_to_string(email_body, context)
. There is no rendering to be done here since email_body
is already a string of content. You can delete that line entirely and use email_body
instead of text
elsewhere in your code.
Alternatively you can create a new template for the text body of the email (maybe email/email_confirm.txt
) and render that instead of using string concatenation to create email_body
.
In the edits, this sequence is problematic:
template = get_template('email/email_confirm.html')
email = render_to_string(template, context)
since render_to_string
takes a path to a template, not the template itself. The fact that get_template
worked here is just an illustration that your template settings are working fine and that email = render_to_string('email/email_confirm.html', context)
was never the issue in the first place and was a bit of a red herring. Once you solve the issue with the text = render_to_string(email_body, context)
line the original code to create the html
variable is fine.
did you tried EmailMultiAlternatives ?
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
def sendMail():
ctx = {
#your context here..
}
html_content = render_to_string('path/to_email.html', context=ctx)
text_content = strip_tags(html_content)
email = EmailMultiAlternatives(
subject= "Activate your Account",
body=text_content,
from_email=settings.EMAIL_HOST_USER,
to=[to_email]
)
email.attach_alternative(html_content,"text/html")
res = email.send()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With