views:

42

answers:

1

Trying to solve a problem with templatetags.

I have two templatetags:

@register.inclusion_tag('directory/_alphabet.html')
def alphabet_list(names):
    """ Return a list of letters that last names start with. """
    return { 'letters': [name.last_name[0] for name in names] }

class NameNode(template.Node):
    def __init__(self, letter, var_name):
        self.letter = letter
        self.var_name = var_name

    def render(self, context):
        context[self.var_name] = Person.objects.get_active().filter(
            last_name__istartswith=self.letter)
        return ''

@register.tag
def get_names(parser, token):
    try:
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires arguments" % \
                token.contents.split()[0]
    m = re.search(r'for (.*?) as (\w+)', arg)
    if not m:
        raise template.TemplateSyntaxError, "%r tag had invalid arguments" % \
              tag_name
    letter, var_name = m.groups()
    return NameNode(letter, var_name)

And I want to use them like so:

{% for letter in letters %}
<h2>{{ letter }}</h2>
{% get_names for letter as names %}
<ul>
    {% for name in names %}
    <li>{{ name }}</li>
    {% endfor %}
</ul>
{% endfor %}

But 'letter' gets sent as the word 'letter' and not as whatever letter the variable should contain. Is there a way around this or something I'm missing (or, better yet, a package that already does this)?

+3  A: 

You get the string "letter" because this is what the template parser read from your template source. If you want to access the value of this variable, you have to mark it as a template variable in NameNode.__init__ and resolve it using the context in render.

As follow:

class NameNode(template.Node):
    def __init__(self, letter, var_name):
        self.letter = template.Variable(letter)
        self.var_name = var_name

    def render(self, context):
        try:
            context[self.var_name] = Person.objects.get_active().filter(
                last_name__istartswith=self.letter.resolve(context))
        except template.VariableDoesNotExist:
            pass
        return ''

It's explained in the docs here.

Clément
Thanks. I read those docs but missed the .resolve() part.
Kenneth Love