I'm building a function to send email and I need to use a context_processor variable inside the HTML template of the email, but this don't work.
Example:
def send_email(plain_body_template_name, html_body_template_name):
plain_body = loader.render_to_string(plain_body_template_name, context)
html_body = loader.render_to_string(html_body_template_name, context)
email_msg = EmailMultiAlternatives(body=plain_body)
email_msg.attach_alternative(html_body, 'text/html')
email_message.send()
In my custom context_processor.py
I just have a function that receive a HttpRequest
and return a dict like {'foo': 'bar'}
, and in the template I try to render using {{foo}}
.
I added the context_processor in the TEMPLATE['OPTIONS']['context_processors']
too.
context_processors is a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.
render_to_string is a callable within the django. template. loader module of the Django project. get_template and select_template are a couple of other callables within the django. template.
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.
template. Context , but Django also comes with a subclass, django. template. RequestContext , that acts slightly differently. RequestContext adds a bunch of variables to your template context by default-things like the HttpRequest object or information about the currently logged-in user.
Assuming you're using the django
backend in your TEMPLATE
with
'BACKEND': 'django.template.backends.django.DjangoTemplates',
django is seeing that you haven't passed in a request and opting for a basic Context
to wrap your dict instead of a RequestContext
which will handle the context_processors
you've defined.
You can probably get away with doing
html_body = loader.render_to_string(html_body_template_name, context, request=request)
but you'd need to pass in the request object.
This might not make sense though. Are you emailing the person making the request? Does the context make sense to include?
If your context processor doesn't need the request
then I'd either make it a simple utility function (if it's only called here) or make the request parameter optional, import it into this module, and add it directly into the context
context = {"my_var": 1}
context.update(your_extra_context())
loader.render_to_string(...)
There are some complicated ways of updating a Context()
in layers, but I don't think that's necessary here.
I had a similar problem - I needed to render template to string with context processor values, but at the same time request object was None (running command from console). Then I found this approach:
from django.template.loader import render_to_string
from django.template import RequestContext
from django.shortcuts import render
def index(request):
if not request:
context = {'param1':'value1'}
return render_to_string('myapp/index.html', RequestContext(None, context))
else:
#render as usual
render(request, 'myapp/index.html', context)
pass
when you pass RequestContext instead of dictionary, it populates values of all context processors into the context. But request must be optional in all your context processors, otherwise this won't work.
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