« Posts tagged Filter

A Simple Django Truncate Filter

The Problem:

The built-in Django filter, truncate_words, truncates a string after a certain number of words.  This is great, but many times I find I have very tight space restrictions in certain areas of a page, and a string that is too long would push its way into another element and subsequently into my head in the form of a headache.

The built-in truncate_words filter is no help here — it does nothing to limit the width of a string.

I.e., “One two” and “ooooooooooooooooooooooooooonnnnnnnnnnnnnnneeeeeeeeeeeeee twoooooooooooooo” are both only 2 words, yet they have extremely different widths :)

The Solution:

We need a filter that truncates not only by words, but by characters too.  It’s an extremely simple filter, and often times I wonder why it’s not included in Django.

Let’s start from the very beginning.  Every filter must live in your app’s templatetags directory.  So create a file in that directory named “truncate_filters.py” or something.  If you need any more information than that, take a look at the Django documentation on how to create a custom filter.

Here is what the filter looks like:

from django import template
register = template.Library()

@register.filter("truncate_chars")
def truncate_chars(value, max_length):
    if len(value) <= max_length:
        return value

    truncd_val = value[:max_length]
    if value[max_length] != " ":
        rightmost_space = truncd_val.rfind(" ")
        if rightmost_space != -1:
            truncd_val = truncd_val[:rightmost_space]

    return truncd_val + "..."


*update* code was changed per chris and paul’s suggestions below, I haven’t tested but assume they work :)

Here’s how it works visually on this string: “This is a sample string”
This is what happens when the filter is supplied with the argument 20:

  1. Cut down the string to 20 chars if it is greater than 20 chars in length.  The string now becomes: “This is a sample str”
  2. Find the right-most space, indicating the start of the last word in the string, and truncate again:  The string is now: “This is a sample”
  3. Add “…” and return.  “This is a sample…”

You can invoke the filter from within your template like so:

{% load truncate_filters %}
<ol>
{% for some_string in a_list_of_strings %}
    <li>{{some_string|truncate_chars:50}}</li>
{% endfor %}
</ol>

Hope someone out there finds this helpful :)

Django: A Profanity Filter

The reason for it:

There are often times when you would like to display content on your page that was actually submitted by another user, such as displaying a list of recent posts on your homepage or something.  The problem is that you don’t want to post any offensive material on such a prominent page.  Without real live human moderation, the best we can do is strip out things we know are offensive (to most people anyway), such as bad words.  Here’s a profanity filter for Django I wrote using code mostly sheisted from django.core.validators.

And here she is:

Here’s what the filter looks like: (If you don’t know how to make a filter in Django, read the documentation)

@register.filter("replace_bad_words")
def replace_bad_words(value):
    """ Replaces profanities in strings with safe words
    For instance, "shit" becomes "s--t"
    """
    words_seen = [w for w in settings.PROFANITIES_LIST if w in value]
    if words_seen:
        for word in words_seen:
            value = value.replace(word, "%s%s%s" % (word[0], '-'*(len(word)-2), word[-1]))
    return value

Some other things:

Just throw that on a django template variable and it will replace words like “shit” with “s–t.” It won’t change words like “ass” and “dick” since they are technically not bad words… but if you think they are, you can do something like this:

...
extra_bad_words = ['ass', 'dick']

bad_words = settings.PROFANITIES_LIST.extend(extra_bad_words)

words_seen = [w for w in bad_words if w in value]
...

Pretty useful huh?

Oh, one more thing to add — this filter depends on the profanities list that is included in Django.  To get this, make sure you import settings:


from django.conf import settings

That’s it.

I know there are a lot of details missing.  I apologize.  If you make a comment here, I’ll be happy to help you out.