views:

435

answers:

2

Can you think of an easy way to evaluate a text field as a template during the template rendering.

I know how to do it in a view but I'm looking for a template Filter or a Tag ?

Something like:

{{ object.textfield|evaluate}} or {% evaluate object.textfield %}

with object.textfield containing something like:

a text with a {% TemplateTag %}.

In which TemplateTag will be evaluated, thanks to the evaluate filter.

A: 

Here is a first Tag implementation to solve my question:

from django import template

register = template.Library()

@register.tag(name="evaluate")
def do_evaluate(parser, token):
    """
    tag usage {% evaluate object.textfield %}
    """
    try:
        tag_name, variable = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
    return EvaluateNode(variable)

class EvaluateNode(template.Node):
    def __init__(self, variable):
        self.variable = template.Variable(variable)

    def render(self, context):
        try:
            content = self.variable.resolve(context)
            t = template.Template(content)
            return t.render(context)
        except template.VariableDoesNotExist, template.TemplateSyntaxError:
            return 'Error rendering', self.variable
Pierre-Jean Coudert
+1  A: 

Hi

It's going to involve regular expressions. Something I'm not so good at, I've written an example but you (or someone else here) will (I guarantee) have a more efficient way of doing this. But this is just an example:

from django.template import Library, Node, TemplateSyntaxError
from django.template import Template, Context

register = Library()

class TemplateEvalNode(Node):
    def __init__(self, value):
        self.value = Variable(value)

    def render(self, context):
        value = self.value.resolve(context)
        regex = re.compile('{% \w+ %}')
        # Grab the template tag (eg. {% TemplateTag %})
        unevaluated_var = regex.search(value)

        if unevaluated_var == None:
            return value

        # Create a template containing only the template tag
        t = Template(unevaluated_var)
        # Evaluate that template (with context)
        return_var = t.render(Context(context))

        # Return the original value with the template tag replaced with
        # its actual value
        return value.replace(unevaluated_var, return_var)

def template_eval(parser, token):
    bits = token.contents.split()
    if len(bits) != 2:
        raise TemplateSyntaxError, "template_eval takes exactly one argument"
    return TemplateEvalNode(bits[1])

template_eval = register.tag(template_eval)

I haven't tested this yet, so it may not work straight off, but in theory you can run:

{% template_eval object.textfield %}

And it would return:

a text with a VALUE_OF_TEMPLATETAG.

Expect an update to this as I'm going to test it now and attempt to fix any problems, my battery is about to die so I'm posting this now untested.

Also expect a much more clever solution from someone who is better at Python than I am :p.

EDIT: OK, I was too slow, you beat me!

Thanks for your response ! Sorry for responding quicker ;-)
Pierre-Jean Coudert