django: Easy way for template tags to add information to template context

0 Comments

I've been seeing a pattern emerging with Django template tags that I've been writing and it's starting to annoy me.

Example usage:

1.{% some_tag by request.user as context_var %}  
2.{% for item in context_var %} ... {% endfor %}

The template tag would be:

01.from django.template import Library, Node, Variable
02. 
03.register = Library()
04. 
05.@register.tag
06.def some_tag(parser, token):
07.  bits = token.split_contents()
08.  tag = bits.pop(0) # pop tag
09.  context_var = None
10. 
11.  if len(bits):
12.    context_var = bits.pop(0)
13. 
14.  user_var = Variable(bits.pop())
15.  return SomeTagNode(context_var, user_var = user_var)
16. 
17.class SomeTagNode(Node):
18.  def __init__(self, context_var, user_var = None):
19.    self.context_var, self.user_var = context_var, user_var
20. 
21.  def render(self, context):
22.    context[self.context_var] = SomeModel.objects.filter(user = self.user_var.resolve(context))
23.    return ''

As you can see, there is some fluffing involved with creating a new class for something that could be done easily. The trick is finding a way to make it easier to re-use.

I found it annoying that registering tags using Library.simple_tag() automatically parses the context values (but did not allow access to it) and Library.inclusion_tag() supported the use of takes_context but the regular Library.tag() didn't.

Place this code in a re-usable file.

1.from django.template import Node
2. 
3.class ContextNode(Node):
4.  def __init__(self, func):
5.    self.func = func
6. 
7.  def render(self, context):
8.    return self.func(context)

Now if you want to create a new tag:

01.from django.template import Library, TemplateSyntaxError, resolve_variable
02. 
03.register = Library()
04. 
05.@register.tag
06.def some_tag(parser, tokens):
07.  bits = token.split_contents()
08.  tag = bits.pop(0) # pop tag
09.  context_var = None
10. 
11.  if len(bits):
12.    context_var = bits.pop(0)
13. 
14.  user_var = bits.pop()
15. 
16.  # This is a wrapper function to accept the context variable
17.  def some_tag_wrap(context):
18.    context[context_var] = SomeModel.objects.filter(user = resolve_variable(user_var, context))
19.    return ''
20. 
21.  return ContextNode(some_tag_wrap)

This makes life much simpler if all you want to do is add a variable to the context.

Also, note the use of resolve_variable(), which gets rid of the repetitively annoying use of Variable.resolve().

Now you can go back to doing things in life that matter.

2602541719_cffba86acc_z

 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog