Usage¶
Tag and the various Arg classes are consciously modelled after Django’s Model, Form, and respective Field classes.
Arg``s are set on a ``Tag in the same way Field``s would be set on a ``Model or Form.
Example¶
Following is a minimal example of a template tag:
class Welcome(ttag.Tag):
def output(self, data):
return "Hi there!"
This would create a tag {% welcome %} which took no arguments and output Hi there!.
Registering your tag¶
TTag Tag classes are registered just like a standard tag:
from django import template
import ttag
register = template.Library()
class Welcome(ttag.Tag):
def output(self, data):
return "Hi there!"
register.tag(Welcome)
Defining arguments¶
Let’s extend the basic example tag above to accept an argument so we can greet the user personally:
class Welcome(ttag.Tag):
user = ttag.Arg(positional=True)
def output(self, data):
name = data['user'].get_full_name()
return "Hi, %s!" % name
The tag now has one positional tag which will be used to get the user from the template context.
Note
Arguments are usually resolved against the template context. For simpler cases, you can use ttag.BasicArg.
Named arguments¶
The other standard argument type is a named argument.
Keyword argument format¶
When using several named arguments, space-separated named arguments can start to look a bit confusing. For these cases, you may want to use the named keyword argument format (name=value):
class Output(ttag.Tag):
limit = self.Arg(keyword=True)
offset = self.Arg(keyword=True)
This would result in a tag like this:
{% output limit=some_limit|default:1 offset=profile.offset %}
Note
If your tag should define a list of arbitrary keywords, you may benefit from ttag.KeywordsArg instead.
Validation arguments¶
Some default classes are included to assist with validation of template arguments.
Altering context¶
Cleaning arguments¶
Writing a block tag¶
For simple block tags, use the block option:
class Repeat(ttag.Tag):
count = ttag.IntegerArg()
class Meta():
block = True
end_block = 'done'
def render(self, context):
data = self.resolve(context)
output = []
for i in range(data['count']):
context.push()
output.append(self.nodelist.render(context))
context.pop()
return ''.join(output)
As you can see, using the block option will add a nodelist attribute to the tag, which can then be rendered using the context.
The optional end_block option allows for an alternate ending block. The default value is 'end%(name)s', so it would be {% endrepeat %} for the above tag if the option hadn’t been provided.
Working with multiple blocks¶
Say we wanted to expand on our repeat tag to look for an {% empty %} alternative section for when a zero-value count is received.
Rather than setting the block option to True, we set it to a dictionary where the keys are the section tags to look for and the values are whether the section is required:
class Repeat(ttag.Tag):
count = ttag.IntegerArg()
class Meta():
block = {'empty': False}
def render(self, context):
data = self.resolve(context)
if not data['count']:
return self.nodelist_empty.render(context)
output = []
for i in range(data['count']):
context.push()
output.append(self.nodelist.render(context))
context.pop()
return ''.join(output)
This will cause two attributes to be added to the tag: nodelist will contain everything collected up to the {% empty %} section tag, and nodelist_empty will contain everything up until the end tag.
If no matching section tag is found when parsing the template, either a TemplateSyntaxError will be raised (if it’s a required section) or an empty node list will be used.
More advanced cases can be handled using Django’s standard parser in the __init__ method of your tag:
class AdvancedTag(ttags.Tag):
def __init__(self, parser, token):
super(Repeat, self).__init__(parser, token)
# Do whatever fancy parser modification you like.
Full Example¶
This example provides a template tag which outputs a tweaked version of the instance name passed in. It demonstrates using the various Arg types:
class TweakName(ttag.Tag):
"""
Provides the tweak_name template tag, which outputs a
slightly modified version of the NamedModel instance passed in.
{% tweak_name instance [offset=0] [limit=10] [reverse] %}
"""
instance = ttag.ModelInstanceArg(positional=True, model=NamedModel))
offset = ttag.IntegerArg(default=0, keyword=True)
limit = ttag.IntegerArg(default=10, keyword=True)
reverse = ttag.BooleanArg()
def clean_limit(self, value):
"""
Check that limit is not negative.
"""
if value < 0:
raise ttag.TagValidationError("limit must be >= 0")
return value
def output(self, data):
name = data['instance'].name
# Reverse if appropriate.
if 'reverse' in data:
name = name[::-1]
# Apply our offset and limit.
name = name[data['offset']:data['offset'] + data['limit']]
# Return the tweaked name.
return name
Example usages:
{% tweak_name obj limit=5 %}
{% tweak_name obj offset=1 %}
{% tweak_name obj reverse %}
{% tweak_name obj offset=1 limit=5 reverse %}