Question

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.

Was it helpful?

Solution

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:

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.

OTHER TIPS

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
]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top