Repeating Sections in a Django Template

I have a need to have multiple sections of name/value pairs with a header on some pages. Something like:

<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>History:</h2></div></div>
        <div class="row"><div class="span2">Date added to fleet:</div><div class="span2">{{plane.dateAddedToFleet}}</div></div>
        <div class="row"><div class="span2">Total Flight Time:</div><div class="span2">{{plane.totalFlightTime|asTime}}</div></div>
        <div class="row"><div class="span2">Total Number of Flights:</div><div class="span2">{{plane.totalNumberOfFlights}}</div></div>
    </div>
</div>

So that’s wrong. I first tried creating a custom tag to render the entire section that would be used like this within the django template:


{% specgroup "History" "Date added to fleet" plane.dateAddedToFleet "Total Flight Time:" plane.totalFlightTime|asTime "Total Number of Flights" plane.totalNumberOfFlights %}

The custom tag code for the above is:


# tags for groups of fields (such as on plane detail page)
@register.simple_tag
def specgroup(*args):
    """group header label1 value1 label2 value2 ...."""
    header= args[0]
    logging.getLogger().error(header)
    html = """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>
"""%header
    # parse remainder of args as  label1 value1 label2 value2 etc....
    data = args[1:]
    diter = iter(data)
    for d in diter:
        data = {}
        data["label"] = d
        data["value"] = diter.next()
        html += """  <div class="row"><div class="span2">%(label)s:</div><div class="span2">%(value)s</div></div>"""%data
    html += """
    </div>
</div>"""
    return html 

You cannot split the arguments across multiple lines to clean up the mess that is the call to the custom tag. So back to the drawing board.

I compromised with this:


{% specheader "History" %}
{% specdata "Date added to fleet" plane.dateAddedToFleet %}
{% specdata "Total Flight Time" plane.totalFlightTime|asTime %}
{% specdata "Total Number of Flights" plane.totalNumberOfFlights %}
{% specend %} 

It’s my favorite compromise between brevity and maintainability.

The custom tags to implement this are:


@register.simple_tag
def specheader(header):
    return """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>"""%header

@register.simple_tag
def specdata(label,value):
    return '<div class="row"><div class="span2">%s:</div><div class="span2">%s</div></div>'%(label, value)

@register.simple_tag
def specend():
    return "</div></div>"

Which is also cleaner than the all-in-one tag.

It’s not for me, but Skylar Savland on github created a Django Template macros with args and kwargs gist that is another solution to this problem.

I’d love to hear ideas that solve this problem in a better way.

This entry was posted in Django, Python. Bookmark the permalink.

8 Responses to Repeating Sections in a Django Template

  1. jt says:

    IMHO, the {% include %} tag is one of the bests methods for doing exactly that. Instead of passing all the parameters in one line, which is ugly, you could pass in the object (in your example the ‘plane’). Or pass nothing at all, because the included template has access to the context (e.g. include something inside a loop…).

    I don’t like to generate tags with such specific markup. I prefer to keep as much as possible all the markup in the templates. However it’s probably a matter of likes :)

    And… When dealing with more complex issues, iterables/querysets that need to render specific markup, I’ve used a great project called django-tables2 project (https://github.com/bradleyayers/django-tables2). It allows you to attach an iterable (e.g. Queryset) to render an HTML table, while providing pagination, sorting, etc. Despite of being intented to render HTML tables, you can easily change the generated markup by defining your own custom template. In your case, it looks like it’s too much powerful because you are not working with data sets (just instances), so it’s probably not worth.

  2. mg says:

    Hi, I’ve stumbled upon your blog quite randomly, but – out of curiosity – are you building some aircraft fleet management system in django? I’m curious since I’m doing such a project right now ;)

  3. Ben says:

    It probably makes more sense when the repeated code is a bit more lengthy, but I’ve always used an {% include %} tag with a {% with %} statement to set the different variables. Keeps your HTML in a template then, albeit another file, rather than inside your template tag.

  4. kpd says:

    Yes I am – kind of. I’m building an online logbook for radio-controlled aircraft at rcfluglog.com.

  5. kpd says:

    Thanks everyone. I agree with you regarding the html code being in a template file as opposed to hard-coded in the tag. I’ll be checking out django-tables2 later today. It sounds interesting (for the moment I’m just using jquery’s datatable to manage that, but that is an interim solution and a piece of technical debt to be addressed.)

  6. migajek says:

    kpd, thank you for your answer :) Good luck then :)
    Since I’m also building similar thing, I needed to have something like django-tables2 but with edit & search. Right now I’m developing something you might be interested in, an integration of django and jqGrid (full featured jQuery grid).
    It’s not as stable and well-documented as django-tables2 but is intended to have more features. you might want to have a look: https://bitbucket.org/migajek/django-tastypie-jqgrid

  7. kpd says:

    Thanks I’ll take a look at that – it sounds very useful.

  8. Ole Laursen says:

    You could put the data in a list or tuple in the view, and iterate over that with a for loop in the template. That way the template has the HTML and the view has the logic. You could then combine that with an include.

    Or you could just use an HTML table and cut down on the tag soup. :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>