Django-like filters for Kid (and Genshi)

This post is deprecated and superseded by this post.


I’ve had a look recently at Django’s templates. I know most of my readers are fans of TurboGears, so if you are one of them, hold yourself from throwing tomatoes at me – I was only playing with it. It was nothing serious.

Then, I came back to Kid, and started to miss Django’s filters. These filters are a lot like UNIX pipes. You can do things like: {{ identity.is_anonymous() | yes_no }}. The output of this will be the value returned by is_anonymous() after being processed by the yes_no filter, which translates a boolean to either “yes” or “no”.

Some filters can do really cool stuff. For instance, consider this:

  • {{ file_size | filesizeformat }}: this would print the size in a human-readable format (i.e. 17 KB, 102.4MB and so on).
  • {{ story.text | escape | linebreaks }}: this will escape all ampersands from the text and then convert all newlines to <p> and <br/>. This also demonstrates that filters can be chained.
  • You have {{egg_count}} egg{{egg_count | pluralize}} left: will pluralize the egg noun with the suffix ‘s’ if egg_count is not one.

“But you can achieve the same by using the existing functional notation!”, I see you thinking. “You can do {{ linebreaks(escape(story.text)) }}. And it has the benefits of using a pure Python expression”. That’s right. But having pipe-notation:

  • is 217% more fun, since it is more intuitive and readable
  • makes it easy to build a standard library of filters which can be commonly used, to the benefit of the frameworks’ users.
  • makes it easy to add project-specific filters, without having to pass them as a template variable (they aren’t).
  • adds a new dimension to Kid or Genshi. Currently they work great on the XML level, which is their primary design goal. But a bit lacking on text interpolation capabilties. The stuff surrounded by those XML tags also matters :)

Then, I thought that there should be no reason that this will not be easy to implement with Kid (or Genshi). Fast forward 30 minutes, and it is now possible to do all the above in Kid. To comply to Kid and Python syntax, it is done with double pipes:

${ story.text || escape || linebreaks }

or

${ story.link || urlize }

The last one converts URLs in the text to a clickable link.

To get a rich set of filters to start with, I just borrowed Django’s default filters module. It was fairly easy to disconnect the dependency of most on them on Django. I threw away the rest for the time being. Adding your own filter is also extremely easy. You can just add to controllers.py the following:

def handle_shorturl(s):
    """Returns the URL without the query string"""
    return s.split('?')[0]

from kid.filterslib import register_filter
register_filter('shorturl', handle_shorturl)

If you’d like to start playing with it as well, I’ve prepared two patches, against Kid 0.9.3 and Kid 0.9.4:

To apply the patch, just cd into the kid directory and type: patch -p1 < djangokid-0.9.4.patch.

For a superset of what is currently implemented, see: Django built-in filter reference.

UPDATE: I've added also a patch for Genshi.

I'm looking forward for your feedback.

This post is deprecated and superseded by this post.
This entry was posted in turbogears. Bookmark the permalink.

8 Responses to Django-like filters for Kid (and Genshi)

  1. Italo Maia says:

    TOO COOL!!! I wanted something like that for a long time! Pipe with templates are really cool!!! Now, we need it with genshi heheh :P.

  2. jorge.vargas says:

    /me puts the tomatoes down…. this seems interesting

    so the idea is to have a library of filters with common functions….

    ok real world test now just one question why will it be usefull to have all this on output side? I mean if I’m always going to

    ${ story.text || escape || linebreaks }

    why not process that when it gets input do it ones and store it like that on the db?

    it could be usefull for something very dynamic but I don’t see much use (other then being cool) on output.

    now implementing it as a decorator or even as some sort of validator could be a more “usefull” way of having pipes.

  3. thesamet says:

    Jorge,

    It is very often than you need to truncate a very long string or convert a boolean to ‘yes’ or ‘no’. It is a form of representation that shouldn’t be kept in the db.

    There are forms of representations that are tightly coupled with the template. For example, when a design of a web page becomes narrower, your want to truncate the strings even more.

  4. Italo Maia says:

    Maybe using pipes with widgets would be nice too. Nadav, what about using double dollar. Like $${}? Would that be very hard to implement, instead of using double pipes? Or ${“some_output | lower | prettier | hot_chik_pretty | turbogears_pretty”} using string. Double pipes seems so wrong to my eyes…(but i’ll use it anyway :P)

    ps: Would patching Genshi the same way as patching kid?

  5. thesamet says:

    Italo, The problem is that one | is a Python operator. It leads to ambiguous expressions. Unfortunately also > and >> are taken. But I’m open to suggestions.

    Patching Genshi was basically dropping the same lines of code, but elsewhere. Genshi itself does things a lot differently than Kid.

  6. Italo Maia says:

    Oh well, can’t think of something better either. Pipes are so perfect :p. Double pipe won’t kill me. ^^

  7. Pingback: Filters 0.1 Released | Nadav Samet’s Blog

  8. pens says:

    Hello nice blog! !!
    pen
    It’s my new page.about pens.

Leave a Reply

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