Django

Code

Changeset 6692

Show
Ignore:
Timestamp:
11/18/07 01:19:11 (11 months ago)
Author:
mtredinnick
Message:

Rewrote the section about writing autoescaping-aware filters, based on feedback
from Ivan Sagalaev.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/docs/templates_python.txt

    r6671 r6692  
    756756   about these; they exist for the implementation of the ``escape`` filter. 
    757757 
    758 Inside your filter, you will need to think about three areas in order to be 
    759 auto-escaping compliant: 
    760  
    761  1. If your filter returns a string that is ready for direct output (it should 
    762     be considered a "safe" string), you should call 
    763     ``django.utils.safestring.mark_safe()`` on the result prior to returning. 
    764     This will turn the result into the appropriate ``SafeData`` type. This is 
    765     often the case when you are returning raw HTML, for example. 
    766  
    767  2. If your filter is given a "safe" string, is it guaranteed to return a 
    768     "safe" string? If so, set the ``is_safe`` attribute on the function to be 
    769     ``True``. For example, a filter that replaced a word consisting only of 
    770     digits with the number spelt out in words is going to be 
    771     safe-string-preserving, since it cannot introduce any of the five dangerous 
    772     characters: <, >, ", ' or &. We can write:: 
     758When you are writing a filter, your code will typically fall into one of two 
     759situations: 
     760 
     761 1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``, 
     762    ``'``, ``"`` or ``&``) into the result that were not already present. In 
     763    this case, you can let Django take care of all the auto-escaping handling 
     764    for you. All you need to do is put the ``is_safe`` attribute on your 
     765    filter function and set it to ``True``. This attribute tells Django that 
     766    is a "safe" string is passed into your filter, the result will still be 
     767    "safe" and if a non-safe string is passed in, Django will automatically 
     768    escape it, if necessary. The reason ``is_safe`` is necessary is because 
     769    there are plenty of normal string operations that will turn a ``SafeData`` 
     770    object back into a normal ``str`` or ``unicode`` object and, rather than 
     771    try to catch them all, which would be very difficult, Django repairs the 
     772    damage after the filter has completed. 
     773 
     774    For example, suppose you have a filter that adds the string ``xx`` to the 
     775    end of any input. Since this introduces no dangerous HTML characters into 
     776    the result (aside from any that were already present), you should mark 
     777    your filter with ``is_safe``:: 
    773778 
    774779        @register.filter 
    775         def convert_to_words(value): 
    776             # ... implementation here ... 
    777             return result 
    778  
    779         convert_to_words.is_safe = True 
    780  
    781     Note that this filter does not return a universally safe result (it does 
    782     not return ``mark_safe(result)``) because if it is handed a raw string such 
    783     as '<a>', this will need further escaping in an auto-escape environment. 
    784     The ``is_safe`` attribute only talks about the the result when a safe 
    785     string is passed into the filter. 
    786  
    787  3. Will your filter behave differently depending upon whether auto-escaping 
    788     is currently in effect or not? This is normally a concern when you are 
    789     returning mixed content (HTML elements mixed with user-supplied content). 
    790     For example, the ``ordered_list`` filter that ships with Django needs to 
    791     know whether to escape its content or not. It will always return a safe 
    792     string. Since it returns raw HTML, we cannot apply escaping to the 
    793     result -- it needs to be done in-situ. 
    794  
    795     For these cases, the filter function needs to be told what the current 
    796     auto-escaping setting is. Set the ``needs_autoescape`` attribute on the 
    797     filter to ``True`` and have your function take an extra argument called 
    798     ``autoescape`` with a default value of ``None``. When the filter is called, 
    799     the ``autoescape`` keyword argument will be ``True`` if auto-escaping is in 
    800     effect. For example, the ``unordered_list`` filter is written as:: 
    801  
    802         def unordered_list(value, autoescape=None): 
    803             # ... lots of code here ... 
    804  
    805             return mark_safe(...) 
    806  
    807         unordered_list.is_safe = True 
    808         unordered_list.needs_autoescape = True 
    809  
    810 By default, both the ``is_safe`` and ``needs_autoescape`` attributes are 
    811 ``False``. You do not need to specify them if ``False`` is an acceptable 
    812 value. 
     780        def add_xx(value): 
     781            return '%sxx' % value 
     782        add_xx.is_safe = True 
     783 
     784    When this filter is used in a template where auto-escaping is enabled, 
     785    Django will escape the output whenever the input is not already marked as 
     786    "safe". 
     787 
     788    By default, ``is_safe`` defaults to ``False`` and you can omit it from 
     789    any filters where it isn't required. 
     790 
     791    Be careful when deciding if your filter really does leave safe strings 
     792    as safe. Sometimes if you are *removing* characters, you can 
     793    inadvertently leave unbalanced HTML tags or entities in the result. 
     794    For example, removing a ``>`` from the input might turn ``<a>`` into 
     795    ``<a``, which would need to be escaped on output to avoid causing 
     796    problems. Similarly, removing a semicolon (``;``) can turn ``&amp;`` 
     797    into ``&amp``, which is no longer a valid entity and thus needs 
     798    further escaping. Most cases won't be nearly this tricky, but keep an 
     799    eye out for any problems like that when reviewing your code. 
     800 
     801 2. Alternatively, your filter code can manually take care of any necessary 
     802    escaping. This is usually necessary when you are introducing new HTML 
     803    markup into the result. You want to mark the output as safe from further 
     804    escaping so that your HTML markup isn't escaped further, so you'll need to 
     805    handle the input yourself. 
     806 
     807    To mark the output as a safe string, use 
     808    ``django.utils.safestring.mark_safe()``. 
     809 
     810    Be careful, though. You need to do more than just mark the output as 
     811    safe. You need to ensure it really *is* safe and what you do will often 
     812    depend upon whether or not auto-escaping is in effect. The idea is to 
     813    write filters than can operate in templates where auto-escaping is either 
     814    on or off in order to make things easier for your template authors. 
     815 
     816    In order for you filter to know the current auto-escaping state, set the 
     817    ``needs_autoescape`` attribute to ``True`` on your function (if you don't 
     818    specify this attribute, it defaults to ``False``). This attribute tells 
     819    Django that your filter function wants to be passed an extra keyword 
     820    argument, called ``autoescape`` that is ``True`` is auto-escaping is in 
     821    effect and ``False`` otherwise. 
     822 
     823    An example might make this clearer. Let's write a filter that emphasizes 
     824    the first character of a string:: 
     825 
     826        from django.utils.html import conditional_escape 
     827        from django.utils.safestring import mark_safe 
     828 
     829        def initial_letter_filter(text, autoescape=None): 
     830            first, other = text[0] ,text[1:] 
     831            if autoescape: 
     832                esc = conditional_escape 
     833            else: 
     834                esc = lambda x: x 
     835            result = '<strong>%s</strong>%s' % (esc(first), esc(other)) 
     836            return mark_safe(result) 
     837        initial_letter_filter.needs_autoescape = True 
     838 
     839    The ``needs_autoescape`` attribute on the filter function and the 
     840    ``autoescape`` keyword argument mean that our function will know whether 
     841    or not automatic escaping is in effect when the filter is called. We use 
     842    ``autoescape`` to decide whether the input data needs to be passed through 
     843    ``django.utils.html.conditional_escape`` or not (in the latter case, we 
     844    just use the identity function as the "escape" function). The 
     845    ``conditional_escape()`` function is like ``escape()`` except it only 
     846    escapes input that is **not** a ``SafeData`` instance. If a ``SafeData`` 
     847    instance is passed to ``conditional_escape()``, the data is returned 
     848    unchanged. 
     849 
     850    Finally, in the above example, we remember to mark the result as safe 
     851    so that our HTML is inserted directly into the template without further 
     852    escaping. 
     853 
     854    There is no need to worry about the ``is_safe`` attribute in this case 
     855    (although including it wouldn't hurt anything). Whenever you are manually 
     856    handling the auto-escaping issues and returning a safe string, the 
     857    ``is_safe`` attribute won't change anything either way. 
    813858 
    814859Writing custom template tags 
     
    933978~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    934979 
    935 The output from template tags is not automatically run through the 
     980**New in Django development version** 
     981 
     982The output from template tags is **not** automatically run through the 
    936983auto-escaping filters. However, there are still a couple of things you should 
    937984keep in mind when writing a template tag: