Wednesday, August 8, 2012

custom template filter

Django comes with many filters and tags, but we can create new filters/tags ourselves, and make them available in template using
{% load %}

first create a new directory templatetags at the same level with views.py and models.py, don't forget to touch a new file __init__.py in that new created directory, then you can create a new module/file which will be the name used as filter's name later(be careful to pick a name to avoid collision with exist filter names). For Example, create a new file in templatetags directory as extra_filters.py, then you can load it in your template as:
{% load extra_filters %}

In order to make your new created filter valid, the module must contain a module level variable register   which is  a template.Library instance,
from django import template
register = template.Library()

And you should register the filter by: if you prefer to use decorator way, you can omit the name='cut' and the filter's name will be the function's name by default, here that's cut.
register.filter('cut', cut) # or

@resigter.filter(name='cut')
def cut(value, args):
    pass

Filters and auto-escaping

when creating custom filters, give some thought to how the filter will interact with django's auto escaping. Three types of strings can be passed around inside the template code,

  • raw string

          Python native str/unicode types, if django's auto escaping is on, they will be    escaped, otherwise keep unchanged


  • Safe string

          They are of type SafeString/SafeUnicode, they are share the same parent SafeData. They commonly used for output includes raw HTML, and the necessary escape has been done.


  • String marked as 'needing escaping'

          These strings are always be escaped regardless of autoescaping is on or not. But they will be escaped only once.


The template filters will fall into two situations:
1,  It won't introduce HTML unsafe characters, django will take care of it, all you need to do is set is_safe to True,
@register.filter(is_safe=True)
def my_filter(value):
    return value

This flag tells django that if a safe string is passed in, the result will be a safe one, otherwise django will escape the result for you. Be careful if this flag is set to True, the result will be a string instead of other python types such as bool, list, etc.

2,  Alternatively, your filter code can manually take care of any necessary escaping. This is necessary when you're introducing new HTML markup into the result. You want to mark the output as safe from further escaping so that your HTML markup isn't escaped further, so you'll need to handle the input yourself.
To mark the output as a safe string, use django.utils.safestring.mark_safe().
Be careful, though. You need to do more than just mark the output as safe. You need to ensure it really is safe, and what you do depends on whether auto-escaping is in effect. The idea is to write filters than can operate in templates where auto-escaping is either on or off in order to make things easier for your template authors.
In order for your filter to know the current auto-escaping state, set the needs_autoescape flag to True when you register your filter function. (If you don't specify this flag, it defaults to False). This flag tells Django that your filter function wants to be passed an extra keyword argument, called autoescape, that is True if auto-escaping is in effect and False otherwise.
For example, let's write a filter that emphasizes the first character of a string:
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe

@register.filter(needs_autoescape=True)
def initial_letter_filter(text, autoescape=None):
    first, other = text[0], text[1:]
    if autoescape:
        esc = conditional_escape
    else:
        esc = lambda x: x
    result = '<strong>%s</strong>%s' % (esc(first), esc(other))
    return mark_safe(result)
The needs_autoescape flag and the autoescape keyword argument mean that our function will know whether automatic escaping is in effect when the filter is called. We use autoescape to decide whether the input data needs to be passed throughdjango.utils.html.conditional_escape or not. (In the latter case, we just use the identity function as the "escape" function.) The conditional_escape() function is like escape() except it only escapes input that is not a SafeData instance. If a SafeData instance is passed to conditional_escape(), the data is returned unchanged.
Finally, in the above example, we remember to mark the result as safe so that our HTML is inserted directly into the template without further escaping.
There's no need to worry about the is_safe flag in this case (although including it wouldn't hurt anything). Whenever you manually handle the auto-escaping issues and return a safe string, the is_safe flag won't change anything either way.

ps: https://docs.djangoproject.com/en/1.4/howto/custom-template-tags/

No comments:

Post a Comment