Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Rewrote the section about writing autoescaping-aware filters, based o…

…n feedback

from Ivan Sagalaev.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@6692 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 86ca11dd6d94cc624d3e20f887a8de39350b3665 1 parent 38d972b
Malcolm Tredinnick authored November 18, 2007

Showing 1 changed file with 101 additions and 54 deletions. Show diff stats Hide diff stats

  1. 155  docs/templates_python.txt
155  docs/templates_python.txt
@@ -755,61 +755,106 @@ inside the template code:
755 755
    ``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry
756 756
    about these; they exist for the implementation of the ``escape`` filter.
757 757
 
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::
  758
+When you are writing a filter, your code will typically fall into one of two
  759
+situations:
  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``::
773 778
 
774 779
         @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.
813 858
 
814 859
 Writing custom template tags
815 860
 ----------------------------
@@ -932,7 +977,9 @@ without having to be parsed multiple times.
932 977
 Auto-escaping considerations
933 978
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
934 979
 
935  
-The output from template tags is not automatically run through the
  980
+**New in Django development version**
  981
+
  982
+The output from template tags is **not** automatically run through the
936 983
 auto-escaping filters. However, there are still a couple of things you should
937 984
 keep in mind when writing a template tag:
938 985
 

0 notes on commit 86ca11d

Please sign in to comment.
Something went wrong with that request. Please try again.