Customization: Custom filters

  1. Custom tags
  2. Customization
  3. Custom admin actions

http://docs.python.org/library/re.html

Filters are the things that use a pipe (|) to alter a value. For example, we used the pipe earlier to filter a number into a word.

Filters require more care, because Django (like many web scripting environments) maintains the concept of “safe” and “unsafe” text. Unsafe text must be “escaped” so that all HTML is not rendered; this avoids cross-site scripting attacks.

So a filter that returns HTML needs to know whether it needs to escape its text before adding the HTML; and then once it adds the HTML it needs to mark the result as safe so that other filters don’t escape it.

This filter will link any mention of a topic to that topic’s page:

from django.utils.safestring import mark_safe

from django.utils.html import conditional_escape

from Blog.postings.models import Topic

import re

@register.filter

def linkTopics(text, autoescape=None):

if autoescape:

topicalText = conditional_escape(text)

linkTemplate = template.loader.get_template('parts/inline_topic.html')

for topic in Topic.objects.all():

regex = re.compile('\\b(' + topic.title + ')\\b', re.IGNORECASE)

replacement = linkTemplate.render(context=template.Context({'topic': topic}))

topicalText = re.sub(regex, replacement, topicalText, 1)

topicalText = mark_safe(topicalText)

return topicalText

linkTopics.needs_autoescape = True

Like the tag, we have to register this filter using a decorator so that Django knows about it. Because this filter is returning HTML, we need to tell Django that the filter needs to know whether or not autoescape is on. That’s what “linkTopics.needs_autoescape = True” does.

If autoescape is on, the text is first escaped, so that HTML tags (such as <script>) are escaped (become &lt;script&gt;).

Then, we load the template for the link so that we can use it over and over again.

Inside the loop, a regular expression converts any occurrence of any topic title to a link to that topic’s page. The replacement is case-insensitive, and happens only to the first instance of the topic title in the text being filtered.

Create parts/inline_topic.html:

<a href="{% url postings.views.topicalPosts topic.slug %}">\1</a>

And load this templatetags file into post.html:

{% load media %}

Replace “{{ post.content|linebreaks }}” with:

{{ post.content|linkTopics|linebreaks }}

You should now see that topics are linked to their listing when you read individual posts. Make the same change to the author’s bio:

{{ post.author.bio|linkTopics|linebreaks }}

If you want, you can go ahead and make the same change in index.html, so that topics are linked in the main listing and in the topics listings.

By putting all of your HTML into templates, you can easily change the HTML without worrying about adding bugs to your code. For example, you can easily add a class of “topics” to the <a> tag in inline_topic.html, and then add a style for it in index.html:

a.topic {

border: solid .1em;

border-top: none;

border-bottom: none;

padding-right: .2em;

padding-left: .2em;

}

Because of template inheritance, that style will also be available on topics pages and post pages.

  1. Custom tags
  2. Customization
  3. Custom admin actions