Ignored By Dinosaurs 🦕

python

Hi there, I'm new to Django. I love the contributed ecosystem, but all of the options that I found there for dealing with Markdown were just too heavy. I didn't need a Wysiwyg editor, I just wanted an output filter. As it turns out this is exceptionally easy to do!


Python has a really amazing lib situation, so I just found the smallest python Markdown lib that I could, it's called “mistune”. Do a pip install mistune.

So within your app, let's call it “blog”, create a directory called templatetags. By the way, this is all pretty easy to parse out of their killer documentation. Create a file in there called markdownify.py.

 # blog/templatetags/markdownify.py
from django import template
import mistune
 
register = template.library()
 
@register.filter
def markdown(value):
	markdown = mistune.Markdown()
	return markdown(value)

It is as simple as that. In whatever template you'll actually want to be rendering markdown, you'll need to include this templatetag with

 {% load markdownify %}

at the top of the template. Then you'll just pipe the output that you want to render like you do in every other template lib —-

{{ post.body | markdown | safe }}

The full example of the template that renders this page is here.


But wait, there's more!

How about syntax highlighting? We're programmers after all, and Python just happens to have the great-granddaddy of all syntax highlighting libs in Pygments. I've known of Pygments for years, since it used to be a requirement of one of the Ruby libs to Markdown rendering (if you wanted synta highlighting). In other words, even Ruby leaned on Pygments for a great number of years.

So pip install pygments. Then scroll down the page on the Mistune docs and follow along. You'll be adding some code to the markdownify.py file.

from django import template
import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter

register = template.Library()

class HighlightRenderer(mistune.Renderer):
    def block_code(self, code, lang):
        if not lang:
            return f"""
```
{mistune.escape(code)}
```
            """
        lexer = get_lexer_by_name(lang, stripall=True)
        formatter = HtmlFormatter()
        return highlight(code, lexer, formatter)

@register.filter
def markdown(value):
    renderer = HighlightRenderer()
    markdown = mistune.Markdown(renderer=renderer)
    return markdown(value)

That HighlightRenderer class is directly out of the Mistune docs, so thank you Mistune Author! That is seriously all it takes, but you'll need a stylesheet, of which there are plenty. I searched for “pygments stylesheets” and came across this project, so you'll need to pick one of those themes and get it into your project somewhere. By default, the zenburn theme is expecting the wrapper div to have a CSS class of 'codehilite' instead of what it needs – 'highlight', so a quick search and replace and I had syntax highlighting in less than 5 minutes.


*edit Sept 2016*

So once you manage your way through all this, you'll be able to use “fenced code blocks” in your posts. They look like this —

```php
<?php 

function foo() {
 /// ...
}
```

becomes

<?php 

function foo() {
 /// ...
}

You can use either a trio of tildes ~ or backticks ` to open and close one of those code blocks, and I typically just pass the file extension and it generally works. You can also write out the full name of the language.

```py
def method():
    return "foo"
```

becomes

def method():
    return "foo"

Just be advised that it is possible to fatally hose your website if you happen to pass a language for which Pygments doesn't have a “lexer”, meaning that it has no idea how to highlight the syntax of that language. That happened to me with some Varnish config files that I tried to highlight with a .vcl extension on them. I don't remember how I fixed it but I'm pretty sure it required going directly to the database to change the post since my site was toast. You are warned.

#python #django

So here it is. The last version of this blog – a Rails frontend to a Postgres backend – actually stood for almost 2 and a half years. I think that's probably a record.

In keeping with my decided new theme for this blog however, I've decided to rewrite the thing in Django. Not that you can't google it yourself, but Django is (at a high level) basically the Python version of Rails. Actually, it's basically the Python version of every MVC web framework. It's been around for 10 years, so it is far from the hot-new-thing. I've finally been doing this for long enough that I shy away from the hot-new-thing and actively seek out boring, tested solutions to problems.

At work we've begun a small project that we were targeting to build on Drupal 8. Faced with the timeframe, the relative lack of basic modules for building Drupal 8 sites, and the learning curve for the code that we'd inevitably have to write on our own I pitched the idea to my team to try something completely different. I prefaced it with “this is a terrible idea, so raise your hand at any point”, but surprisingly they were all amenable. We all spent a day going through the amazing tutorial and the amazing documentation and they were still on board. So I decided to rebuild this blog to take the training wheels off and give us all some reference code for some of the simple features that weren't walked through in the tutorial – taxonomy, sitemaps, extending templates, etc.

Amazingly it took me all of 4 hours to rebuild the whole thing and migrate the data from one PG schema into the one that Django wants to use. Django is even easier to use than Rails – a fact that blew my mind once I started playing with it.

The deployment story however, is a shit show. I spent as many days trying to get this thing up on a Digital Ocean server as I spent hours building the application in the first place. I'm hoping to find that there is an easier, more modern means for serving Python apps in 2016 after some more digging.

Anyway, thanks for stopping by!

#generaldevelopment #python #django