Check if a block is defined in Django
Very often when styling a webpage, you want to put content in a box. For example, say you have a standard box for contextual help content.
<div class="help">
<!--- actual html contents here --->
</div>
<style>
.help {
padding: 1em;
border: 1px dashed black;
}
</style>
A sensible way to make this re-usable in Django would be to use blocks.
<div class="help">
{% block help %}{% endblock %}
</div>
But what happens if no help block is defined? With this implementation, you would still get the empty help DIV, complete with a border and padding. Of course, you could render the div inside the block, but then you're repeating yourself every time you define one.
One work-around is via css:empty.
<style>
.help:empty {
disply: none;
}
</style>
However, that approach will not work in all browsers/versions. Also, it's muddying the separation between content and style.
Ideally, you would be able to omit the div at the base template level if the block is not defined. I wondered if there was an way to check if a block is defined. While hunting around, I found the next best thing. The following code (from kcarnold) will capture the contents of a block to a variable. You can then conditionally render it only if it exists and is not empty.
from django import template
register = template.Library()
@register.tag(name='captureas')
def do_captureas(parser, token):
try:
tag_name, args = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
nodelist = parser.parse(('endcaptureas',))
parser.delete_first_token()
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 ''
{% captureas help_content %}{% spaceless %}{% block help %}{% endblock %}{% endspaceless %}{% endcaptureas %}
{% if help_content %}
<div id="help">
{{ help_content }}
</div>
{% endif %}
Django actually may add this functionality natively in the future.