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

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:

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

The template tag would be:

from django.template import Library, Node, Variable

register = Library()

@register.tag
def some_tag(parser, token):
bits = token.split_contents()
tag = bits.pop(0) # pop tag
context_var = None

if len(bits):
context_var = bits.pop(0)

user_var = Variable(bits.pop())
return SomeTagNode(context_var, user_var = user_var)

class SomeTagNode(Node):
def __init__(self, context_var, user_var = None):
self.context_var, self.user_var = context_var, user_var

def render(self, context):
context[self.context_var] = SomeModel.objects.filter(user = self.user_var.resolve(context))
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.

from django.template import Node

class ContextNode(Node):
def __init__(self, func):
self.func = func

def render(self, context):
return self.func(context)

Now if you want to create a new tag:

from django.template import Library, TemplateSyntaxError, resolve_variable

register = Library()

@register.tag
def some_tag(parser, tokens):
bits = token.split_contents()
tag = bits.pop(0) # pop tag
context_var = None

if len(bits):
context_var = bits.pop(0)

user_var = bits.pop()

# This is a wrapper function to accept the context variable
def some_tag_wrap(context):
context[context_var] = SomeModel.objects.filter(user = resolve_variable(user_var, context))
return ''

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