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.