how to stop django template code from escaping - django

Is there any way to completely turn off django auto_escaping when rendering a template within the view code (for an email for example):
from django.template import Context, Template
subject_template_string = "Hi {{ customer.name }}"
subject_template = Template(subject)
context = Context({'customer':MyCustomerModel.objects.get(pk=1)})
subject = subject_template.render(context)
If customer.name is something like "Jack & Jill" - the subject looks like "Hi Jack &\amp; Jill" (without the backslash!)
is there something like
subject = subject_template.render(context, autoescape=False)
edit: The actual templates are created by the client in the database, I'm hoping to avoid having to say add |safe to all templates where this might happen...

Disabling it globally is usually a bad idea since you can easily forget it. I would recommend using the templatetag to disable it for that portion of your template instead.
Something like this:
{% autoescape off %}
This will not be auto-escaped: {{ data }}.
Nor this: {{ other_data }}
{% autoescape on %}
Auto-escaping applies again: {{ name }}
{% endautoescape %}
{% endautoescape %}

How about using mark_safe:
Explicitly mark a string as safe for (HTML) output purposes. The
returned object can be used everywhere a string or unicode object is
appropriate.
It marks a string as safe, so, you should take customer.name out and pass to the template:
from django.utils.safestring import mark_safe
customer = MyCustomerModel.objects.get(pk=1)
context = Context({'customer_name': mark_safe(customer.name)})
subject = subject_template.render(context)
Though, control what is safe or not is better to do inside the template itself, that's why using autoescape should be preffered.

Use Django's autoescape tag:
{% autoescape off %}
{{ body }}
{% endautoescape %}
for more info, check out the docs here.

This is untested, but based on source code review it looks like the context object can take autoescape as a key.
context = Context({'customer':MyCustomerModel.objects.get(pk=1), 'autoescape': False})
subject = subject_template.render(context)
That said, that's a pretty sweeping change. If you know what values the templates might be looking for, it's probably better to use mark_safe on those values and pass in the predefined options. That would have the added benefit of not risking the possibility of the client template calling a method with side effects on the customer. The first time someone writes a template and puts in {{ customer.delete }}, you have a problem.

Just came back to answer my own question with a simple solution, and there were already 4 answers.. thanks.
This is what I've gone with:
subject_template = Template(u'{%% autoescape off %%}%s{%% endautoescape %%}' % email.subject)

Related

Django Template: Dynamic template variable inside another variable

I hope this makes sense... I am building a crypto asset list page (easy); however, in the {% for %} loop I would like to include a variable inside a variable. Showing the code will make more sense:
Tempalte.html
{% for crypto_asset in objects__list_cryptoAssets %}
<tr role="row" class="body-row">
<td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
</tr>
{% endfor %}
So the {% for %} loop grabs all the crypto assets and then I can use Django template {{ asset_class.slug }} to grab all slugs... nothing exceptional here. This variable {{ api_external_prices.bitcoin.usd }} grabs external USD prices for Bitcoin, {{ api_external_prices.bitcoin.eur }} prices in EUR, and so forth... nothing exceptional here either.
Here is where the question comes :: the idea would be to have something like {{ api_external_prices.{{ asset_class.slug }}.usd }}... so each crypto would have its own price FX fetched correctly. Is it possible to have a variable inside a variable?
They are several ways you can implement this:
Template filters
You can create a template filter api_external_prices that takes asset_class and the crypto type as parameters and returns the value.
The syntax would be something link this, where api_external_prices is the name of the template filter:
{{ asset_class|api_external_prices:"usd" }}
See here for more info about this feature: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#writing-custom-template-filters
Methods
Another approach would be to have api_external_prices as method on your asset_class object, which returns an object that has a usd property. api_external_prices here can just be a wrapper that calls a central module/function, but this would make it much easier to use it in templates.
{{ asset_class.api_external_prices.usd }}
The first approach is similar to what you are asking, but personally I would prefer to use the 2nd approach, because it saves you from introducing as template filter.

Django template variable containing template tag, ex {{ {% some_tag %} }}

I have a template that receives a list context variable, tags_list. I need to iterate over this list 'inserting' the tags in the template something like this:
{% for tag in tags_list %}
{{ tag.tag }}
{% endfor %}
When this renders it returns the text value of tag.tag, "{% tagxxx %}", not the rendered tag.
How can I cause the template render to render the value of a context variable? Alternately, is there a filter, a sort of inverse verbatim, that will cause the value of a context variable to be rendered?
Updated background
tags_list is created by a fairly sophisticated process involving exec of some user provided text from a table/model field. The relevant portion of the real template looks like this:
{% for graph_row in graph_rows %}
<div class="row">
{% for graph in graph_row %}
<div class="col-md-{{ graph.width }}">
{{ graph.graph }}
</div>
{% endfor %}
</div>
{% endfor %}
The graph values look like this: {'graph':'{% piechart data1 %}', 'width':3}
Note that the order of entries in the context variable graph_rows is significant as is order of graph(s) in the row as that determines the placement of graphs on the page. Preserving this order is essential for the scheme to work correctly.
Currently, the view function simply does an {% include ... %} to get the template segment above to render in the correct order. This approach is simple and clean.
I could, as has been suggested, perform a template render within the view function but that complicates the design a bit and I'd hoped to avoid doing that if there is an easy way to trigger a render of {{ graph.graph }}. Note, as well, by moving the render into the view I loose the ability to easily take the template from arbitrary places, in particular table fields.
One of the great things about Django is the library of solution and code snippets. Sadly, they aren't a well organized and easy to find as one might wish. Nevertheless, a bit of google found a number of solutions of the general form
{% render tag.tag %}
Here are links to several:
render_as_template template tag
Allow template tags in a Flatpage's content
render_as_template.py
I'll use the general approach cleaned up a bit for error checking.
As an aside, the technique strikes me as generally useful and might be appropriate for inclusion in the standard tags.
Update 3/28/2014
After looking at the above and several others this is what I used from render_as_template template tag. There is a useful comment here.
from django import template
from django.template import Template, Variable, TemplateSyntaxError
register = template.Library()
class RenderAsTemplateNode(template.Node):
def __init__(self, item_to_be_rendered):
self.item_to_be_rendered = Variable(item_to_be_rendered)
def render(self, context):
try:
actual_item = self.item_to_be_rendered.resolve(context)
return Template(actual_item).render(context)
except template.VariableDoesNotExist:
return ''
def render_as_template(parser, token):
bits = token.split_contents()
if len(bits) !=2:
raise TemplateSyntaxError("'%s' takes only one argument"
" (a variable representing a template to render)" % bits[0])
return RenderAsTemplateNode(bits[1])
render_as_template = register.tag(render_as_template)
This gets part of the way to a solution. Unfortunately custom template tags, in my case
{% pie_chart %} are not available to render within the class RenderAsTemplateNode.
I've not tested this but it appears that this stack overflow question, Django - replacing built-in templatetag by custom tag for a whole site without {% load .. %}, points the way.
I believe I can provide a way for you to get the results you want, but there might be a better way for you to achieve the desired functionality if you can provide some context.
Anyway, you might do something like this in your view.py:
tags_list = [
Template('{% load my_tags %}{% ' + t.tag + ' %}').render(Context())
for t in tags_list
]

Customizing django object parameters value output

what does django do, when i do something like that in template
{{ object.parameter }}
I ask this because in case of arrayfields (postgresql array fields) it will print out either
{'value', 'value', 'value'}
(because thats how postgresql stores arrays in arrayfields)
or
['value','value','value']
if i use fields post_init method to convert postgresql array to python list.
Desired output would of course be value, value, value. I would rather not use some kind of filters for that, because then i would have to resort using IFs in templates or use some kind of template tag filter for every value i print out and that does not feel like a smart thing to do.
By the way, i know i can do something like that in template :
{% for choice in field.choices %}
{{ choice }}
{% if forloop.last %}
{% else %},
{% endif%}
{% endfor %}
and that gives me exactly what i want, but i thought there would be some other way doing it - with some modelfield method or something.
Alan
what does django do, when i do something like that in template
{{ object.parameter }}
See variables and lookups.
Desired output would of course be value, value, value. I would rather not use some kind of filters for that, because then i would have to resort using IFs in templates or use some kind of template tag filter for every value i print out and that does not feel like a smart thing to do.
You can make a really trivial filter:
#register.filter
def comma_join(values):
return u', '.join(values)
So simple:
{{ object.parameter|comma_join }}
Why would you want to avoid such a simple solution ?
and that gives me exactly what i want, but i thought there would be some other way doing it - with some modelfield method or something.
Of course you could also add such a method:
class YourModel(models.Model):
# ....
def comma_join_parameter(self):
return u', '.join(self.parameter)
And use it in your template as such:
{{ object.comma_join_parameter }}

Django Custom Template Tag with Context Variable Argument

I have a custom template tag which shows a calendar. I want to populate certain items on the calendar based on a dynamic value.
Here's the tag:
#register.inclusion_tag("website/_calendar.html")
def calendar_table(post):
post=int(post)
imp=IMP.objects.filter(post__pk=post)
if imp:
...do stuff
In my template, it works fine when I pass a hard coded value, such as
{% load inclusion_tags %}
{% calendar_table "6" %}
However when I try something like {% calendar_table "{{post.id}}" %} , it raises a error a ValueError for the int() attempt. How can I get around this?
You want {% calendar_table post.id %}; the extra {{ and }} are what are causing you the heartburn.
Note that, in your custom tag, you need to take the string ("post.id") that gets passed and resolve it against the context using Variable.resolve. There's more information on that in the Django docs; in particular, look here: http://docs.djangoproject.com/en/1.3/howto/custom-template-tags/#passing-template-variables-to-the-tag

Django - use template tag and 'with'?

I have a custom template tag:
def uploads_for_user(user):
uploads = Uploads.objects.filter(uploaded_by=user, problem_upload=False)
num_uploads = uploads.count()
return num_uploads
and I'd like to do something like this, so I can pluralize properly:
{% with uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
{% endwith %}
However, uploads_for_user leader doesn't work in this context, because the 'with' tag expects a single value - Django returns:
TemplateSyntaxError at /upload/
u'with' expected format is 'value as name'
Any idea how I can get round this?
You could turn it into a filter:
{% with user|uploads_for as upload_count %}
While a filter would still work, the current answer to this question would be to use assignment tags, introduced in Django 1.4.
So the solution would be very similar to your original attempt:
{% uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
Update: As per the docs assignment tags are deprecated since Django 1.9 (simple_tag can now store results in a template variable and should be used instead)
In Django 1.9 django.template.Library.assignment_tag() is depricated:
simple_tag can now store results in a template variable and should be used instead.
So, now simple tag we can use like a:
It’s possible to store the tag results in a template variable rather
than directly outputting it. This is done by using the as argument
followed by the variable name. Doing so enables you to output the
content yourself where you see fit:
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>