Django Template Tag for Truncating Characters at a Word Boundary

The default truncatechars template tag truncates a string if it is longer than the specified number of characters but does so exactly at the character count, irrespective of whether it’s the middle of a word or not.

Here’s a smarter version that clips the text at the word boundary:

from django import template
register = template.Library()
# truncate chars but leaving last word complete
def smart_truncate_chars(value, max_length):
if len(value) > max_length:
# limits the number of characters in value to max_length (blunt cut)
truncd_val = value[:max_length]
# check if the next upcoming character after the limit is not a space,
# in which case it might be a word continuing
if value[max_length] != ' ':
# rfind will return the last index where matching the searched character,
# in this case we are looking for the last space
# then we only return the number of character up to that last space
truncd_val = truncd_val[:truncd_val.rfind(' ')]
return truncd_val + '…'
return value

Conditional Output of a Django Block

A common use case when developing Django templates is rendering a block only when the block has content. Take this for example:

<section id="message" class="messages alert">
<p>{% block message %}{% endblock %}</p>

view raw
hosted with ❤ by GitHub

If you use blocks as designed out of the box, you’ll end up with some extra markup that you may need to hide via other methods (such as CSS). That’s definitely not ideal.

After digging around for a bit I stumbled upon this very helpful snippet which accomplishes this using a custom template tag:

from django import template
register = template.Library()
def do_captureas(parser, token):
tag_name, args = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
nodelist = parser.parse(('endcaptureas',))
return CaptureasNode(nodelist, args)
class CaptureasNode(template.Node):
def __init__(self, nodelist, varname):
self.nodelist = nodelist
self.varname = varname
def render(self, context):
output = self.nodelist.render(context)
context[self.varname] = output
return ''

view raw
hosted with ❤ by GitHub

The tag captures the content of the block to a variable within the template which can then be tested for existence, allowing you to conditionally show the block depending on the contents.

Using the tag is as simple as this:

{% load captureas %}
{% captureas message %}{% spaceless %}{% block message %}{% endblock %}{% endspaceless %}{% endcaptureas %}
{% if message %}
<section id="message" class="messages alert">
<p>{{ message }}</p>
{% endif %}

view raw
hosted with ❤ by GitHub

Hopefully Django adds this in the future.