views:

191

answers:

2

If I have created a template tag:

@register.simple_tag
def last_books(a_cat, cutoff=5):
    objects = Books.objects.filter(category=a_cat)
    return objects[:cutoff]

How can I do something like this in my template:

{% for book in last_books 'Sports' 3 %}

I am currently getting this error:

'for' statements should use the format 'for x in y': for x in last_books 'Sports' 3

A: 

Why not with?

ohnoes
Perhaps I'm using "with" incorrectly? When I try: {% with last_books 'Sports' 3 as book_list %}I get this error:u'with' expected format is 'value as name'
Steve
+4  A: 

Personally, I would simply pass in the book as a context variable via the view. That way you have no need for a template tag.

Alternately, you could use the inclusion_tag decorator instead, which wraps up the idea of rendering an include template with a custom context into the current document.

But if you want to continue on the current path, the simple_tag decorator isn't the way to go. It's for use when you need to return a string which you want rendered directly into the template. What you're trying to do is set a template context variable. This is a bit more involved, but not too difficult. Create a node something like this:

class LastBooksNode(template.Node):
    def __init__(self, a_cat, cutoff=5, var_name='books'):
        self.a_cat = a_cat
        self.cutoff = cutoff
        self.var_name = var_name
    def render(self, context):
        context[self.var_name] = Books.objects.filter(category=self.a_cat)[:self.cutoff]
        return ''

@register.tag(name='last_books')
def do_last_books( parser, token ):
    error = False
    try:
        tag_name, a_cat, cutoff, _as, var_name = token.split_contents()
        if _as != 'as':
            error = True
    except:
        error = True

    if error:
        raise TemplateSyntaxError, 'last_books must be of the form, "last_books <a_cat> <cutoff> as <var_name>'
    else:
        return LastBooksNode( a_cat, cutoff, var_name )

You would then invoke the template tag with:

{% import <your tag library> %}
{% last_books 'cat' 5 as my_books %}
{% for book in my_books %}
    ....
{% endfor %}

Untested, but I hope this demonstrates the idea. As mentioned above, though, passing the books directly to the view via the context or using an inclusion_tag may be easier if you don't intend to reuse this in multiple places.

Daniel
You should include an example of the tag usage such as {% last_books 'Sports' 3 as my_books %}
ironfroggy
You're right, I updated the code sample with more information
Daniel
Awesome, this works great. Thanks! Things are starting to make more sense to me now.
Steve