Markdown tag for django

May 23, 2008

I've fallen in love with markdown. It's really simple and easy to use -- and results in cleaner, more readable, and compliant HTML than I end up with when I code it by hand.

I also love Django, a fantastic python web development framework. And it even has out-of-the-box support for markdown as a template filter. But I don't use django just to do standard database-driven blogging stuff like this blog -- I also use it to run my whole web site, and use it to organize a lot of projects and pages for which the individual look and feel of the page is an integral part of the content. This means that I can't just plug some "data" about a project into a template -- the template is the product. Consequently, many of my pages are their own one-off templates. But that means there are many cases where the content I want to use markdown with isn't coming from some variable from a database, but is part of a template that I'm writing.

Long story short: I want markdown as a template tag, not just as a filter. So I wrote a very simple template tag to do this:

:::python
# markdown_tag.py: a markdown template tag for django.
from django.contrib.markup.templatetags import markup
from django import template
register = template.Library()

@register.tag(name = "markdown")
def markdown_tag(parser, token):
    args = token.contents[len("markdown"):].strip()
    nodelist = parser.parse(('endmarkdown',))
    parser.delete_first_token()
    return MarkdownNode(nodelist, args)

class MarkdownNode(template.Node):
    def __init__(self, nodelist, args):
        self.nodelist = nodelist
        self.args = args
    def render(self, context):
        output = self.nodelist.render(context)
        return markup.markdown(output, self.args)

To use this, save it as "markdown_tag.py", and put it in a "templatetags" directory in your application, like so:

-  project/
     - application/
         - models.py
         - views.py
         - urls.py
         -  templatetags/
             - markdown_tag.py

Then, in your template, include the following:

{%load markdown_tag %}
...
{% markdown %}
# This is a markdowned heading!
{% endmarkdown %}

This also supports extensions, if you have the latest version of markdown - as in this example, with the codehilite extension:

{% markdown codehilite %}
    :::python
    print Hello, world!
{% endmarkdown %}