i cannot wrap my head round this lambda function (render). It's from a Mezzanine util:
def send_mail_template(subject, template, addr_from, addr_to, context=None,
attachments=None, fail_silently=None, addr_bcc=None,
headers=None):
"""
Send email rendering text and html versions for the specified
template name using the context dictionary passed in.
EDITED FOR SIMPLICITY
"""
context.update(context_settings())
# Loads a template passing in vars as context.
render = lambda type: loader.get_template("%s.%s" %
(template, type)).render(Context(context))
# Create and send email.
msg = EmailMultiAlternatives(subject, render("txt"),
addr_from, addr_to, addr_bcc,
headers=headers)
msg.attach_alternative(render("html"), "text/html")
msg.send(fail_silently=fail_silently)
I'm trying to pass a list of templates into my own version of the function. so the parameter "template", which is a string of a path to a template, becomes a list (templates) of strings of paths. Then i need to iterate over the list and apply whatever is happening in the lambda, then call the .render(Context(context)) on it.
this is the ugliest code ever but this shows what i need as an end result:
render = lambda type: loader.get_template("%s.%s" %
(templates[0], type))
render2 = lambda type: loader.get_template("%s.%s" %
(templates[1], type))
# Create and send email.
msg = EmailMultiAlternatives(subject,(render("txt")+render2('txt')).render(Context(context)),
addr_from, addr_to, addr_bcc,
headers=headers)
msg.attach_alternative((render("html")+render2('html').render(Context(context)), "text/html")
msg.send(fail_silently=fail_silently)
The above does work but is obviously just disgusting and the list will be of unknown length.
Please! Can anyone de-construct the lambda function?
Answer with help from Arthur Tacca
I'm trying to build an email body by stacking templates together, so need to pass in a list of templates that will be rendered as the txt and html body together as one. here's what works:
def render_templates(types,templates,context):
template_body = ''
for template in templates:
template_body += loader.get_template("%s.%s" % (template, types)).render(Context(context))
return template_body
def send_mail_template(subject, templates, addr_from, addr_to, context=None,
attachments=None, fail_silently=None, addr_bcc=None,
headers=None):
"""
...
"""
context.update(context_settings())
msg = EmailMultiAlternatives(subject, render_templates("txt",templates,context),
addr_from, to, [],
headers)
msg.attach_alternative(render_templates("html",templates,context), "text/html")
msg.send(fail_silently=fail_silently)
I'm not clear on why you're using a function/lambda at all rather than just (for the first example):
rendered = loader.get_template("%s.%s" % (template, "txt")).render(Context(context))
I guess this simplification only works because you've simplified the context you're doing this in; maybe in the real code you need to pass the render function somewhere to be called later. If not, you can get rid of the lambdas altogether.
Here's a minor point but it might make things a little bit clearer: There is absolutely no difference between
render = lambda type: loader.get_template("%s.%s" %
(templates[0], type))
render2 = lambda type: loader.get_template("%s.%s" %
(templates[1], type))
and:
def render(type):
return loader.get_template("%s.%s" % (templates[0], type))
def render2(type):
return loader.get_template("%s.%s" % (templates[1], type))
(OK, one slight difference is that you get a clearer stack trace if there is an exception.) In fact the second form is better style (AKA is "more Pythonic"); the only reason to use a lambda is if the function is so short that it gets passed to another function without even assigning it to a variable.
In your case this means you can use an iteration if you like:
def render_all(types):
result_list = []
for type, template in zip(types, templates):
result_list.append(loader.get_template("%s.%s" % (template, type)))
return "".join(result_list)
This is ripe for a list comprehension / generator:
def render_all(types):
return "".join(loader.get_template("%s.%s" % (template, type))
for type, template in zip(types, templates))