summaryrefslogtreecommitdiff
path: root/docs/templates_python.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/templates_python.txt')
-rw-r--r--docs/templates_python.txt142
1 files changed, 134 insertions, 8 deletions
diff --git a/docs/templates_python.txt b/docs/templates_python.txt
index bd105888ce..e4658f6461 100644
--- a/docs/templates_python.txt
+++ b/docs/templates_python.txt
@@ -219,13 +219,13 @@ be replaced with the name of the invalid variable.
While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool,
it is a bad idea to turn it on as a 'development default'.
-
+
Many templates, including those in the Admin site, rely upon the
silence of the template system when a non-existent variable is
encountered. If you assign a value other than ``''`` to
``TEMPLATE_STRING_IF_INVALID``, you will experience rendering
problems with these templates and sites.
-
+
Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled
in order to debug a specific template problem, then cleared
once debugging is complete.
@@ -722,6 +722,95 @@ decorator instead::
If you leave off the ``name`` argument, as in the second example above, Django
will use the function's name as the filter name.
+Filters and auto-escaping
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+When you are writing a custom filter, you need to give some thought to how
+this filter will interact with Django's auto-escaping behaviour. Firstly, you
+should realise that there are three types of strings that can be passed around
+inside the template code:
+
+ * raw strings are the native Python ``str`` or ``unicode`` types. On
+ output, they are escaped if auto-escaping is in effect and presented
+ unchanged, otherwise.
+
+ * "safe" strings are strings that are safe from further escaping at output
+ time. Any necessary escaping has already been done. They are commonly used
+ for output that contains raw HTML that is intended to be intrepreted on the
+ client side.
+
+ Internally, these strings are of type ``SafeString`` or ``SafeUnicode``,
+ although they share a common base class in ``SafeData``, so you can test
+ for them using code like::
+
+ if isinstance(value, SafeData):
+ # Do something with the "safe" string.
+
+ * strings which are marked as "needing escaping" are *always* escaped on
+ output, regardless of whether they are in an ``autoescape`` block or not.
+ These strings are only escaped once, however, even if auto-escaping
+ applies. This type of string is internally represented by the types
+ ``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry
+ about these; they exist for the implementation of the ``escape`` filter.
+
+Inside your filter, you will need to think about three areas in order to be
+auto-escaping compliant:
+
+ 1. If your filter returns a string that is ready for direct output (it should
+ be considered a "safe" string), you should call
+ ``django.utils.safestring.mark_safe()`` on the result prior to returning.
+ This will turn the result into the appropriate ``SafeData`` type. This is
+ often the case when you are returning raw HTML, for example.
+
+ 2. If your filter is given a "safe" string, is it guaranteed to return a
+ "safe" string? If so, set the ``is_safe`` attribute on the function to be
+ ``True``. For example, a filter that replaced a word consisting only of
+ digits with the number spelt out in words is going to be
+ safe-string-preserving, since it cannot introduce any of the five dangerous
+ characters: <, >, ", ' or &. We can write::
+
+ @register.filter
+ def convert_to_words(value):
+ # ... implementation here ...
+ return result
+
+ convert_to_words.is_safe = True
+
+ Note that this filter does not return a universally safe result (it does
+ not return ``mark_safe(result)``) because if it is handed a raw string such
+ as '<a>', this will need further escaping in an auto-escape environment.
+ The ``is_safe`` attribute only talks about the the result when a safe
+ string is passed into the filter.
+
+ 3. Will your filter behave differently depending upon whether auto-escaping
+ is currently in effect or not? This is normally a concern when you are
+ returning mixed content (HTML elements mixed with user-supplied content).
+ For example, the ``ordered_list`` filter that ships with Django needs to
+ know whether to escape its content or not. It will always return a safe
+ string. Since it returns raw HTML, we cannot apply escaping to the
+ result -- it needs to be done in-situ.
+
+ For these cases, the filter function needs to be told what the current
+ auto-escaping setting is. Set the ``needs_autoescape`` attribute on the
+ filter to ``True`` and have your function take an extra argument called
+ ``autoescape`` with a default value of ``None``. When the filter is called,
+ the ``autoescape`` keyword argument will be ``True`` if auto-escaping is in
+ effect. For example, the ``unordered_list`` filter is written as::
+
+ def unordered_list(value, autoescape=None):
+ # ... lots of code here ...
+
+ return mark_safe(...)
+
+ unordered_list.is_safe = True
+ unordered_list.needs_autoescape = True
+
+By default, both the ``is_safe`` and ``needs_autoescape`` attributes are
+``False``. You do not need to specify them if ``False`` is an acceptable
+value.
+
Writing custom template tags
----------------------------
@@ -840,6 +929,43 @@ Ultimately, this decoupling of compilation and rendering results in an
efficient template system, because a template can render multiple context
without having to be parsed multiple times.
+Auto-escaping considerations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The output from template tags is not automatically run through the
+auto-escaping filters. However, there are still a couple of things you should
+keep in mind when writing a template tag:
+
+If the ``render()`` function of your template stores the result in a context
+variable (rather than returning the result in a string), it should take care
+to call ``mark_safe()`` if appropriate. When the variable is ultimately
+rendered, it will be affected by the auto-escape setting in effect at the
+time, so content that should be safe from further escaping needs to be marked
+as such.
+
+Also, if your template tag creates a new context for performing some
+sub-rendering, you should be careful to set the auto-escape attribute to the
+current context's value. The ``__init__`` method for the ``Context`` class
+takes a parameter called ``autoescape`` that you can use for this purpose. For
+example::
+
+ def render(self, context):
+ # ...
+ new_context = Context({'var': obj}, autoescape=context.autoescape)
+ # ... Do something with new_context ...
+
+This is not a very common situation, but it is sometimes useful, particularly
+if you are rendering a template yourself. For example::
+
+ def render(self, context):
+ t = template.load_template('small_fragment.html')
+ return t.render(Context({'var': obj}, autoescape=context.autoescape))
+
+If we had neglected to pass in the current ``context.autoescape`` value to our
+new ``Context`` in this example, the results would have *always* been
+automatically escaped, which may not be the desired behaviour if the template
+tag is used inside a ``{% autoescape off %}`` block.
+
Registering the tag
~~~~~~~~~~~~~~~~~~~
@@ -917,7 +1043,7 @@ current context, available in the ``render`` method::
def __init__(self, date_to_be_formatted, format_string):
self.date_to_be_formatted = date_to_be_formatted
self.format_string = format_string
-
+
def render(self, context):
try:
actual_date = resolve_variable(self.date_to_be_formatted, context)
@@ -934,26 +1060,26 @@ format it accordingly.
``template.resolve_variable()`` is still available, but has been deprecated
in favor of a new ``template.Variable`` class. Using this class will usually
be more efficient than calling ``template.resolve_variable``
-
+
To use the ``Variable`` class, simply instantiate it with the name of the
variable to be resolved, and then call ``variable.resolve(context)``. So,
in the development version, the above example would be more correctly
written as:
-
+
.. parsed-literal::
-
+
class FormatTimeNode(template.Node):
def __init__(self, date_to_be_formatted, format_string):
self.date_to_be_formatted = **Variable(date_to_be_formatted)**
self.format_string = format_string
-
+
def render(self, context):
try:
actual_date = **self.date_to_be_formatted.resolve(context)**
return actual_date.strftime(self.format_string)
except template.VariableDoesNotExist:
return ''
-
+
Changes are highlighted in bold.
Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot