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.



I'm currently working at NerdWallet, a startup in San Francisco trying to bring clarity to all of life's financial decisions. We're hiring like crazy. Hit me up on Twitter, I would love to talk.

Follow @chase_seibert on Twitter