Ticket #17135: 17135.2.patch

File 17135.2.patch, 12.5 KB (added by Aymeric Augustin, 13 years ago)
  • docs/howto/custom-template-tags.txt

     
    143143If you leave off the ``name`` argument, as in the second example above, Django
    144144will use the function's name as the filter name.
    145145
    146 Template filters that expect strings
    147 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    148 
    149 If you're writing a template filter that only expects a string as the first
    150 argument, you should use the decorator ``stringfilter``. This will
    151 convert an object to its string value before being passed to your function:
    152 
    153 .. code-block:: python
    154 
    155     from django import template
    156     from django.template.defaultfilters import stringfilter
    157 
    158     register = template.Library()
    159 
    160     @register.filter
    161     @stringfilter
    162     def lower(value):
    163         return value.lower()
    164 
    165 This way, you'll be able to pass, say, an integer to this filter, and it
    166 won't cause an ``AttributeError`` (because integers don't have ``lower()``
    167 methods).
    168 
    169146Filters and auto-escaping
    170147~~~~~~~~~~~~~~~~~~~~~~~~~
    171148
     
    324301   handle the auto-escaping issues and return a safe string, the
    325302   ``is_safe`` attribute won't change anything either way.
    326303
     304Template filters that expect strings
     305~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     306
     307If you're writing a template filter that only expects a string as the first
     308argument, you should use the decorator ``stringfilter``. This will
     309convert an object to its string value before being passed to your function:
     310
     311.. code-block:: python
     312
     313    from django import template
     314    from django.template.defaultfilters import stringfilter
     315
     316    register = template.Library()
     317
     318    @register.filter
     319    @stringfilter
     320    def lower(value):
     321        return value.lower()
     322
     323This way, you'll be able to pass, say, an integer to this filter, and it
     324won't cause an ``AttributeError`` (because integers don't have ``lower()``
     325methods).
     326
     327If you want to set the ``is_safe`` or ``needs_autoescape`` attributes on your
     328filter, pass them as keyword arguments to ``stringfilter``, like this::
     329
     330    @register.filter
     331    @stringfilter(is_safe=True)
     332    def lower(value):
     333        return value.lower()
     334
     335.. warning::
     336
     337    Setting ``is_safe`` or ``needs_autoescape`` directly on a function decorated
     338    by ``stringfilter`` does not work.
     339
    327340Writing custom template tags
    328341----------------------------
    329342
  • django/template/defaultfilters.py

     
    2727# STRING DECORATOR    #
    2828#######################
    2929
    30 def stringfilter(func):
     30def stringfilter(func=None, **flags):
    3131    """
    3232    Decorator for filters which should only receive unicode objects. The object
    3333    passed as the first positional argument will be converted to a unicode
    3434    object.
    3535    """
     36    if func is None:
     37        # @stringfilter(is_safe=..., needs_autoescape=...)
     38        return lambda f: _stringfilter(f, **flags)
     39    else:
     40        # @stringfilter
     41        return _stringfilter(func)
     42
     43def _stringfilter(func, **flags):
    3644    def _dec(*args, **kwargs):
    3745        if args:
    3846            args = list(args)
     
    4553    # arguments by the template parser).
    4654    _dec._decorated_function = getattr(func, '_decorated_function', func)
    4755    for attr in ('is_safe', 'needs_autoescape'):
    48         if hasattr(func, attr):
     56        if attr in flags:
     57            setattr(func, attr, flags[attr])
     58            setattr(_dec, attr, flags[attr])
     59        elif hasattr(func, attr):
    4960            setattr(_dec, attr, getattr(func, attr))
    5061    return wraps(func)(_dec)
    5162
     
    5465###################
    5566
    5667@register.filter
    57 @stringfilter
     68@stringfilter(is_safe=True)
    5869def addslashes(value):
    5970    """
    6071    Adds slashes before quotes. Useful for escaping strings in CSV, for
     
    6273    filter instead.
    6374    """
    6475    return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'")
    65 addslashes.is_safe = True
    6676
    6777@register.filter
    68 @stringfilter
     78@stringfilter(is_safe=True)
    6979def capfirst(value):
    7080    """Capitalizes the first character of the value."""
    7181    return value and value[0].upper() + value[1:]
    72 capfirst.is_safe = True
    7382
    7483@register.filter("escapejs")
    7584@stringfilter
     
    7887    return escapejs(value)
    7988
    8089@register.filter("fix_ampersands")
    81 @stringfilter
     90@stringfilter(is_safe=True)
    8291def fix_ampersands_filter(value):
    8392    """Replaces ampersands with ``&`` entities."""
    8493    return fix_ampersands(value)
    85 fix_ampersands_filter.is_safe = True
    8694
    8795# Values for testing floatformat input against infinity and NaN representations,
    8896# which differ across platforms and Python versions.  Some (i.e. old Windows
     
    175183floatformat.is_safe = True
    176184
    177185@register.filter
    178 @stringfilter
     186@stringfilter(is_safe=True)
    179187def iriencode(value):
    180188    """Escapes an IRI value for use in a URL."""
    181189    return force_unicode(iri_to_uri(value))
    182 iriencode.is_safe = True
    183190
    184191@register.filter
    185 @stringfilter
     192@stringfilter(is_safe=True, needs_autoescape=True)
    186193def linenumbers(value, autoescape=None):
    187194    """Displays text with line numbers."""
    188195    lines = value.split(u'\n')
     
    196203        for i, line in enumerate(lines):
    197204            lines[i] = (u"%0" + width  + u"d. %s") % (i + 1, escape(line))
    198205    return mark_safe(u'\n'.join(lines))
    199 linenumbers.is_safe = True
    200 linenumbers.needs_autoescape = True
    201206
    202207@register.filter
    203 @stringfilter
     208@stringfilter(is_safe=True)
    204209def lower(value):
    205210    """Converts a string into all lowercase."""
    206211    return value.lower()
    207 lower.is_safe = True
    208212
    209213@register.filter
    210 @stringfilter
     214@stringfilter(is_safe=False)
    211215def make_list(value):
    212216    """
    213217    Returns the value turned into a list.
     
    216220    For a string, it's a list of characters.
    217221    """
    218222    return list(value)
    219 make_list.is_safe = False
    220223
    221224@register.filter
    222 @stringfilter
     225@stringfilter(is_safe=True)
    223226def slugify(value):
    224227    """
    225228    Normalizes string, converts to lowercase, removes non-alpha characters,
     
    228231    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
    229232    value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
    230233    return mark_safe(re.sub('[-\s]+', '-', value))
    231 slugify.is_safe = True
    232234
    233235@register.filter
    234236def stringformat(value, arg):
     
    248250stringformat.is_safe = True
    249251
    250252@register.filter
    251 @stringfilter
     253@stringfilter(is_safe=True)
    252254def title(value):
    253255    """Converts a string into titlecase."""
    254256    t = re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
    255257    return re.sub("\d([A-Z])", lambda m: m.group(0).lower(), t)
    256 title.is_safe = True
    257258
    258259@register.filter
    259 @stringfilter
     260@stringfilter(is_safe=True)
    260261def truncatechars(value, arg):
    261262    """
    262263    Truncates a string after a certain number of characters.
     
    268269    except ValueError: # Invalid literal for int().
    269270        return value # Fail silently.
    270271    return Truncator(value).chars(length)
    271 truncatechars.is_safe = True
    272272
    273273@register.filter
    274 @stringfilter
     274@stringfilter(is_safe=True)
    275275def truncatewords(value, arg):
    276276    """
    277277    Truncates a string after a certain number of words.
     
    285285    except ValueError: # Invalid literal for int().
    286286        return value # Fail silently.
    287287    return Truncator(value).words(length, truncate=' ...')
    288 truncatewords.is_safe = True
    289288
    290289@register.filter
    291 @stringfilter
     290@stringfilter(is_safe=True)
    292291def truncatewords_html(value, arg):
    293292    """
    294293    Truncates HTML after a certain number of words.
     
    302301    except ValueError: # invalid literal for int()
    303302        return value # Fail silently.
    304303    return Truncator(value).words(length, html=True, truncate=' ...')
    305 truncatewords_html.is_safe = True
    306304
    307305@register.filter
    308 @stringfilter
     306@stringfilter(is_safe=False)
    309307def upper(value):
    310308    """Converts a string into all uppercase."""
    311309    return value.upper()
    312 upper.is_safe = False
    313310
    314311@register.filter
    315 @stringfilter
     312@stringfilter(is_safe=False)
    316313def urlencode(value, safe=None):
    317314    """
    318315    Escapes a value for use in a URL.
     
    326323    if safe is not None:
    327324        kwargs['safe'] = safe
    328325    return urlquote(value, **kwargs)
    329 urlencode.is_safe = False
    330326
    331327@register.filter
    332 @stringfilter
     328@stringfilter(is_safe=True, needs_autoescape=True)
    333329def urlize(value, autoescape=None):
    334330    """Converts URLs in plain text into clickable links."""
    335331    return mark_safe(urlize_impl(value, nofollow=True, autoescape=autoescape))
    336 urlize.is_safe = True
    337 urlize.needs_autoescape = True
    338332
    339333@register.filter
    340 @stringfilter
     334@stringfilter(is_safe=True, needs_autoescape=True)
    341335def urlizetrunc(value, limit, autoescape=None):
    342336    """
    343337    Converts URLs into clickable links, truncating URLs to the given character
     
    347341    """
    348342    return mark_safe(urlize_impl(value, trim_url_limit=int(limit), nofollow=True,
    349343                            autoescape=autoescape))
    350 urlizetrunc.is_safe = True
    351 urlizetrunc.needs_autoescape = True
    352344
    353345@register.filter
    354 @stringfilter
     346@stringfilter(is_safe=False)
    355347def wordcount(value):
    356348    """Returns the number of words."""
    357349    return len(value.split())
    358 wordcount.is_safe = False
    359350
    360351@register.filter
    361 @stringfilter
     352@stringfilter(is_safe=True)
    362353def wordwrap(value, arg):
    363354    """
    364355    Wraps words at specified line length.
     
    366357    Argument: number of characters to wrap the text at.
    367358    """
    368359    return wrap(value, int(arg))
    369 wordwrap.is_safe = True
    370360
    371361@register.filter
    372 @stringfilter
     362@stringfilter(is_safe=True)
    373363def ljust(value, arg):
    374364    """
    375365    Left-aligns the value in a field of a given width.
     
    377367    Argument: field size.
    378368    """
    379369    return value.ljust(int(arg))
    380 ljust.is_safe = True
    381370
    382371@register.filter
    383 @stringfilter
     372@stringfilter(is_safe=True)
    384373def rjust(value, arg):
    385374    """
    386375    Right-aligns the value in a field of a given width.
     
    388377    Argument: field size.
    389378    """
    390379    return value.rjust(int(arg))
    391 rjust.is_safe = True
    392380
    393381@register.filter
    394 @stringfilter
     382@stringfilter(is_safe=True)
    395383def center(value, arg):
    396384    """Centers the value in a field of a given width."""
    397385    return value.center(int(arg))
    398 center.is_safe = True
    399386
    400387@register.filter
    401388@stringfilter
     
    414401###################
    415402
    416403@register.filter("escape")
    417 @stringfilter
     404@stringfilter(is_safe=True)
    418405def escape_filter(value):
    419406    """
    420407    Marks the value as a string that should not be auto-escaped.
    421408    """
    422409    return mark_for_escaping(value)
    423 escape_filter.is_safe = True
    424410
    425411@register.filter
    426 @stringfilter
     412@stringfilter(is_safe=True)
    427413def force_escape(value):
    428414    """
    429415    Escapes a string's HTML. This returns a new string containing the escaped
     
    431417    possible escaping).
    432418    """
    433419    return mark_safe(escape(value))
    434 force_escape.is_safe = True
    435420
    436421@register.filter("linebreaks")
    437 @stringfilter
     422@stringfilter(is_safe=True, needs_autoescape=True)
    438423def linebreaks_filter(value, autoescape=None):
    439424    """
    440425    Replaces line breaks in plain text with appropriate HTML; a single
     
    443428    """
    444429    autoescape = autoescape and not isinstance(value, SafeData)
    445430    return mark_safe(linebreaks(value, autoescape))
    446 linebreaks_filter.is_safe = True
    447 linebreaks_filter.needs_autoescape = True
    448431
    449432@register.filter
    450 @stringfilter
     433@stringfilter(is_safe=True, needs_autoescape=True)
    451434def linebreaksbr(value, autoescape=None):
    452435    """
    453436    Converts all newlines in a piece of plain text to HTML line breaks
     
    458441    if autoescape:
    459442        value = escape(value)
    460443    return mark_safe(value.replace('\n', '<br />'))
    461 linebreaksbr.is_safe = True
    462 linebreaksbr.needs_autoescape = True
    463444
    464445@register.filter
    465 @stringfilter
     446@stringfilter(is_safe=True)
    466447def safe(value):
    467448    """
    468449    Marks the value as a string that should not be auto-escaped.
    469450    """
    470451    return mark_safe(value)
    471 safe.is_safe = True
    472452
    473453@register.filter
    474454def safeseq(value):
     
    481461safeseq.is_safe = True
    482462
    483463@register.filter
    484 @stringfilter
     464@stringfilter(is_safe=True)
    485465def removetags(value, tags):
    486466    """Removes a space separated list of [X]HTML tags from the output."""
    487467    tags = [re.escape(tag) for tag in tags.split()]
     
    491471    value = starttag_re.sub(u'', value)
    492472    value = endtag_re.sub(u'', value)
    493473    return value
    494 removetags.is_safe = True
    495474
    496475@register.filter
    497 @stringfilter
     476@stringfilter(is_safe=True)
    498477def striptags(value):
    499478    """Strips all [X]HTML tags."""
    500479    return strip_tags(value)
    501 striptags.is_safe = True
    502480
    503481###################
    504482# LISTS           #
Back to Top