Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Implemented auto-escaping of variable output in templates. Fully cont…

…rollable by template authors and it's possible to write filters and templates that simulataneously work in both auto-escaped and non-auto-escaped environments if you need to. Fixed #2359

See documentation in templates.txt and templates_python.txt for how everything
works.

Backwards incompatible if you're inserting raw HTML output via template variables.

Based on an original design from Simon Willison and with debugging help from Michael Radziej.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@6671 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 356662cf74c99fac90afb0f5e6aac8d2d573e62a 1 parent babfe78
Malcolm Tredinnick authored November 14, 2007

Showing 53 changed files with 1,202 additions and 322 deletions. Show diff stats Hide diff stats

  1. 6  django/contrib/admin/filterspecs.py
  2. 3  django/contrib/admin/models.py
  3. 2  django/contrib/admin/templates/admin/base_site.html
  4. 4  django/contrib/admin/templates/admin/change_form.html
  5. 4  django/contrib/admin/templates/admin/date_hierarchy.html
  6. 4  django/contrib/admin/templates/admin/delete_confirmation.html
  7. 2  django/contrib/admin/templates/admin/edit_inline_stacked.html
  8. 4  django/contrib/admin/templates/admin/edit_inline_tabular.html
  9. 6  django/contrib/admin/templates/admin/index.html
  10. 2  django/contrib/admin/templates/admin/invalid_setup.html
  11. 6  django/contrib/admin/templates/admin/object_history.html
  12. 2  django/contrib/admin/templates/admin/pagination.html
  13. 8  django/contrib/admin/templates/admin_doc/model_detail.html
  14. 2  django/contrib/admin/templates/widget/foreign.html
  15. 2  django/contrib/admin/templates/widget/one_to_one.html
  16. 17  django/contrib/admin/templatetags/admin_list.py
  17. 17  django/contrib/admin/templatetags/admin_modify.py
  18. 3  django/contrib/admin/templatetags/adminapplist.py
  19. 3  django/contrib/admin/utils.py
  20. 3  django/contrib/admin/views/decorators.py
  21. 3  django/contrib/admin/views/doc.py
  22. 29  django/contrib/admin/views/main.py
  23. 7  django/contrib/csrf/middleware.py
  24. 13  django/contrib/databrowse/datastructures.py
  25. 12  django/contrib/databrowse/plugins/calendars.py
  26. 10  django/contrib/databrowse/plugins/fieldchoices.py
  27. 3  django/contrib/databrowse/sites.py
  28. 8  django/contrib/flatpages/views.py
  29. 4  django/contrib/humanize/templatetags/humanize.py
  30. 10  django/contrib/markup/templatetags/markup.py
  31. 6  django/contrib/markup/tests.py
  32. 3  django/contrib/sitemaps/templates/sitemap.xml
  33. 3  django/contrib/sitemaps/templates/sitemap_index.xml
  34. 15  django/newforms/forms.py
  35. 8  django/newforms/util.py
  36. 40  django/newforms/widgets.py
  37. 43  django/oldforms/__init__.py
  38. 70  django/template/__init__.py
  39. 5  django/template/context.py
  40. 173  django/template/defaultfilters.py
  41. 37  django/template/defaulttags.py
  42. 6  django/utils/encoding.py
  43. 33  django/utils/html.py
  44. 124  django/utils/safestring.py
  45. 30  django/views/debug.py
  46. 149  docs/templates.txt
  47. 142  docs/templates_python.txt
  48. 4  tests/regressiontests/defaultfilters/tests.py
  49. 2  tests/regressiontests/forms/forms.py
  50. 2  tests/regressiontests/forms/tests.py
  51. 3  tests/regressiontests/humanize/tests.py
  52. 220  tests/regressiontests/templates/filters.py
  53. 207  tests/regressiontests/templates/tests.py
6  django/contrib/admin/filterspecs.py
@@ -9,6 +9,8 @@
9 9
 from django.db import models
10 10
 from django.utils.encoding import smart_unicode, iri_to_uri
11 11
 from django.utils.translation import ugettext as _
  12
+from django.utils.html import escape
  13
+from django.utils.safestring import mark_safe
12 14
 import datetime
13 15
 
14 16
 class FilterSpec(object):
@@ -39,7 +41,7 @@ def title(self):
39 41
     def output(self, cl):
40 42
         t = []
41 43
         if self.has_output():
42  
-            t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % self.title())
  44
+            t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % escape(self.title()))
43 45
 
44 46
             for choice in self.choices(cl):
45 47
                 t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
@@ -47,7 +49,7 @@ def output(self, cl):
47 49
                      iri_to_uri(choice['query_string']),
48 50
                      choice['display']))
49 51
             t.append('</ul>\n\n')
50  
-        return "".join(t)
  52
+        return mark_safe("".join(t))
51 53
 
52 54
 class RelatedFilterSpec(FilterSpec):
53 55
     def __init__(self, f, request, params, model):
3  django/contrib/admin/models.py
@@ -3,6 +3,7 @@
3 3
 from django.contrib.auth.models import User
4 4
 from django.utils.translation import ugettext_lazy as _
5 5
 from django.utils.encoding import smart_unicode
  6
+from django.utils.safestring import mark_safe
6 7
 
7 8
 ADDITION = 1
8 9
 CHANGE = 2
@@ -49,4 +50,4 @@ def get_admin_url(self):
49 50
         Returns the admin URL to edit the object represented by this log entry.
50 51
         This is relative to the Django admin index page.
51 52
         """
52  
-        return u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id)
  53
+        return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, self.object_id))
2  django/contrib/admin/templates/admin/base_site.html
... ...
@@ -1,7 +1,7 @@
1 1
 {% extends "admin/base.html" %}
2 2
 {% load i18n %}
3 3
 
4  
-{% block title %}{{ title|escape }} | {% trans 'Django site admin' %}{% endblock %}
  4
+{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
5 5
 
6 6
 {% block branding %}
7 7
 <h1 id="site-name">{% trans 'Django administration' %}</h1>
4  django/contrib/admin/templates/admin/change_form.html
@@ -10,8 +10,8 @@
10 10
 {% block breadcrumbs %}{% if not is_popup %}
11 11
 <div class="breadcrumbs">
12 12
      <a href="../../../">{% trans "Home" %}</a> &rsaquo;
13  
-     <a href="../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
14  
-     {% if add %}{% trans "Add" %} {{ opts.verbose_name|escape }}{% else %}{{ original|truncatewords:"18"|escape }}{% endif %}
  13
+     <a href="../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
  14
+     {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
15 15
 </div>
16 16
 {% endif %}{% endblock %}
17 17
 {% block content %}<div id="content-main">
4  django/contrib/admin/templates/admin/date_hierarchy.html
... ...
@@ -1,9 +1,9 @@
1 1
 {% if show %}
2 2
 <div class="xfull">
3 3
 <ul class="toplinks">
4  
-{% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title|escape }}</a></li>{% endif %}
  4
+{% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title }}</a></li>{% endif %}
5 5
 {% for choice in choices %}
6  
-<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title|escape }}{% if choice.link %}</a>{% endif %}</li>
  6
+<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title }}{% if choice.link %}</a>{% endif %}</li>
7 7
 {% endfor %}
8 8
 </ul><br class="clear" />
9 9
 </div>
4  django/contrib/admin/templates/admin/delete_confirmation.html
@@ -3,7 +3,7 @@
3 3
 {% block breadcrumbs %}
4 4
 <div class="breadcrumbs">
5 5
      <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
6  
-     <a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
  6
+     <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
7 7
      <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo;
8 8
      {% trans 'Delete' %}
9 9
 </div>
@@ -13,7 +13,7 @@
13 13
     <p>{% blocktrans with object|escape as escaped_object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p>
14 14
     <ul>
15 15
     {% for obj in perms_lacking %}
16  
-        <li>{{ obj|escape }}</li>
  16
+        <li>{{ obj }}</li>
17 17
     {% endfor %}
18 18
     </ul>
19 19
 {% else %}
2  django/contrib/admin/templates/admin/edit_inline_stacked.html
... ...
@@ -1,7 +1,7 @@
1 1
 {% load admin_modify %}
2 2
 <fieldset class="module aligned">
3 3
    {% for fcw in bound_related_object.form_field_collection_wrappers %}
4  
-      <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst|escape }}&nbsp;#{{ forloop.counter }}</h2>
  4
+      <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }}&nbsp;#{{ forloop.counter }}</h2>
5 5
       {% if bound_related_object.show_url %}{% if fcw.obj.original %}
6 6
       <p><a href="/r/{{ fcw.obj.original.content_type_id }}/{{ fcw.obj.original.id }}/">View on site</a></p>
7 7
       {% endif %}{% endif %}
4  django/contrib/admin/templates/admin/edit_inline_tabular.html
... ...
@@ -1,10 +1,10 @@
1 1
 {% load admin_modify %}
2 2
 <fieldset class="module">
3  
-   <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst|escape }}</h2><table>
  3
+   <h2>{{ bound_related_object.relation.opts.verbose_name_plural|capfirst }}</h2><table>
4 4
    <thead><tr>
5 5
    {% for fw in bound_related_object.field_wrapper_list %}
6 6
       {% if fw.needs_header %}
7  
-         <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst|escape }}</th>
  7
+         <th{{ fw.header_class_attribute }}>{{ fw.field.verbose_name|capfirst }}</th>
8 8
       {% endif %}
9 9
    {% endfor %}
10 10
    </tr></thead>
6  django/contrib/admin/templates/admin/index.html
@@ -19,9 +19,9 @@
19 19
         {% for model in app.models %}
20 20
             <tr>
21 21
             {% if model.perms.change %}
22  
-                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name|escape }}</a></th>
  22
+                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
23 23
             {% else %}
24  
-                <th scope="row">{{ model.name|escape }}</th>
  24
+                <th scope="row">{{ model.name }}</th>
25 25
             {% endif %}
26 26
 
27 27
             {% if model.perms.add %}
@@ -58,7 +58,7 @@
58 58
             {% else %}
59 59
             <ul class="actionlist">
60 60
             {% for entry in admin_log %}
61  
-            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst|escape %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
  61
+            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
62 62
             {% endfor %}
63 63
             </ul>
64 64
             {% endif %}
2  django/contrib/admin/templates/admin/invalid_setup.html
... ...
@@ -1,7 +1,7 @@
1 1
 {% extends "admin/base_site.html" %}
2 2
 {% load i18n %}
3 3
 
4  
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title|escape }}</div>{% endblock %}
  4
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title }}</div>{% endblock %}
5 5
 
6 6
 {% block content %}
7 7
 
6  django/contrib/admin/templates/admin/object_history.html
... ...
@@ -1,7 +1,7 @@
1 1
 {% extends "admin/base_site.html" %}
2 2
 {% load i18n %}
3 3
 {% block breadcrumbs %}
4  
-<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name|escape }}</a> &rsaquo; <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
  4
+<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
5 5
 {% endblock %}
6 6
 
7 7
 {% block content %}
@@ -23,8 +23,8 @@
23 23
         {% for action in action_list %}
24 24
         <tr>
25 25
             <th scope="row">{{ action.action_time|date:_("DATE_WITH_TIME_FULL") }}</th>
26  
-            <td>{{ action.user.username }}{% if action.user.first_name %} ({{ action.user.first_name|escape }} {{ action.user.last_name|escape }}){% endif %}</td>
27  
-            <td>{{ action.change_message|escape }}</td>
  26
+            <td>{{ action.user.username }}{% if action.user.first_name %} ({{ action.user.first_name }} {{ action.user.last_name }}){% endif %}</td>
  27
+            <td>{{ action.change_message }}</td>
28 28
         </tr>
29 29
         {% endfor %}
30 30
         </tbody>
2  django/contrib/admin/templates/admin/pagination.html
@@ -6,6 +6,6 @@
6 6
     {% paginator_number cl i %}
7 7
 {% endfor %}
8 8
 {% endif %}
9  
-{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name|escape }}{% else %}{{ cl.opts.verbose_name_plural|escape }}{% endifequal %}
  9
+{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name|escape }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
10 10
 {% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
11 11
 </p>
8  django/contrib/admin/templates/admin_doc/model_detail.html
@@ -8,16 +8,16 @@
8 8
 </style>
9 9
 {% endblock %}
10 10
 
11  
-{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Models</a> &rsaquo; {{ name|escape }}</div>{% endblock %}
  11
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> &rsaquo; <a href="../../">Documentation</a> &rsaquo; <a href="../">Models</a> &rsaquo; {{ name }}</div>{% endblock %}
12 12
 
13  
-{% block title %}Model: {{ name|escape }}{% endblock %}
  13
+{% block title %}Model: {{ name }}{% endblock %}
14 14
 
15 15
 {% block content %}
16 16
 <div id="content-main">
17  
-<h1>{{ summary|escape }}</h1>
  17
+<h1>{{ summary }}</h1>
18 18
 
19 19
 {% if description %}
20  
-  <p>{% filter escape|linebreaksbr %}{% trans description %}{% endfilter %}</p>
  20
+  <p>{% filter linebreaksbr %}{% trans description %}{% endfilter %}</p>
21 21
 {% endif %}
22 22
 
23 23
 <div class="module">
2  django/contrib/admin/templates/widget/foreign.html
@@ -15,6 +15,6 @@
15 15
         {{ bound_field.original_value }}
16 16
     {% endif %}
17 17
     {% if bound_field.raw_id_admin %}
18  
-        {% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %}
  18
+        {% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}
19 19
     {% endif %}
20 20
 {% endif %}
2  django/contrib/admin/templates/widget/one_to_one.html
... ...
@@ -1,2 +1,2 @@
1 1
 {% if add %}{% include "widget/foreign.html" %}{% endif %}
2  
-{% if change %}{% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14"|escape }}</strong>{% endif %}{% endif %}
  2
+{% if change %}{% if bound_field.existing_display %}&nbsp;<strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}{% endif %}
17  django/contrib/admin/templatetags/admin_list.py
@@ -4,8 +4,9 @@
4 4
 from django.core.exceptions import ObjectDoesNotExist
5 5
 from django.db import models
6 6
 from django.utils import dateformat
7  
-from django.utils.html import escape
  7
+from django.utils.html import escape, conditional_escape
8 8
 from django.utils.text import capfirst
  9
+from django.utils.safestring import mark_safe
9 10
 from django.utils.translation import get_date_formats, get_partial_date_formats, ugettext as _
10 11
 from django.utils.encoding import smart_unicode, smart_str, force_unicode
11 12
 from django.template import Library
@@ -19,9 +20,9 @@ def paginator_number(cl,i):
19 20
     if i == DOT:
20 21
         return u'... '
21 22
     elif i == cl.page_num:
22  
-        return u'<span class="this-page">%d</span> ' % (i+1)
  23
+        return mark_safe(u'<span class="this-page">%d</span> ' % (i+1))
23 24
     else:
24  
-        return u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1)
  25
+        return mark_safe(u'<a href="%s"%s>%d</a> ' % (cl.get_query_string({PAGE_VAR: i}), (i == cl.paginator.pages-1 and ' class="end"' or ''), i+1))
25 26
 paginator_number = register.simple_tag(paginator_number)
26 27
 
27 28
 def pagination(cl):
@@ -117,7 +118,7 @@ def result_headers(cl):
117 118
 
118 119
 def _boolean_icon(field_val):
119 120
     BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'}
120  
-    return u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val)
  121
+    return mark_safe(u'<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val))
121 122
 
122 123
 def items_for_result(cl, result):
123 124
     first = True
@@ -193,10 +194,10 @@ def items_for_result(cl, result):
193 194
             # Convert the pk to something that can be used in Javascript.
194 195
             # Problem cases are long ints (23L) and non-ASCII strings.
195 196
             result_id = repr(force_unicode(getattr(result, pk)))[1:]
196  
-            yield (u'<%s%s><a href="%s"%s>%s</a></%s>' % \
197  
-                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), result_repr, table_tag))
  197
+            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
  198
+                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
198 199
         else:
199  
-            yield (u'<td%s>%s</td>' % (row_class, result_repr))
  200
+            yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr)))
200 201
 
201 202
 def results(cl):
202 203
     for res in cl.result_list:
@@ -220,7 +221,7 @@ def date_hierarchy(cl):
220 221
         day_lookup = cl.params.get(day_field)
221 222
         year_month_format, month_day_format = get_partial_date_formats()
222 223
 
223  
-        link = lambda d: cl.get_query_string(d, [field_generic])
  224
+        link = lambda d: mark_safe(cl.get_query_string(d, [field_generic]))
224 225
 
225 226
         if year_lookup and month_lookup and day_lookup:
226 227
             day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
17  django/contrib/admin/templatetags/admin_modify.py
@@ -3,6 +3,8 @@
3 3
 from django.template import loader
4 4
 from django.utils.text import capfirst
5 5
 from django.utils.encoding import force_unicode
  6
+from django.utils.safestring import mark_safe
  7
+from django.utils.html import escape
6 8
 from django.db import models
7 9
 from django.db.models.fields import Field
8 10
 from django.db.models.related import BoundRelatedObject
@@ -32,7 +34,8 @@ def include_admin_script(script_path):
32 34
     """
33 35
     if not absolute_url_re.match(script_path):
34 36
         script_path = '%s%s' % (settings.ADMIN_MEDIA_PREFIX, script_path)
35  
-    return u'<script type="text/javascript" src="%s"></script>' % script_path
  37
+    return mark_safe(u'<script type="text/javascript" src="%s"></script>'
  38
+            % script_path)
36 39
 include_admin_script = register.simple_tag(include_admin_script)
37 40
 
38 41
 def submit_row(context):
@@ -63,8 +66,10 @@ def field_label(bound_field):
63 66
             class_names.append('inline')
64 67
         colon = ":"
65 68
     class_str = class_names and u' class="%s"' % u' '.join(class_names) or u''
66  
-    return u'<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \
67  
-        force_unicode(capfirst(bound_field.field.verbose_name)), colon)
  69
+    return mark_safe(u'<label for="%s"%s>%s%s</label> ' %
  70
+            (bound_field.element_id, class_str,
  71
+            escape(force_unicode(capfirst(bound_field.field.verbose_name))),
  72
+            colon))
68 73
 field_label = register.simple_tag(field_label)
69 74
 
70 75
 class FieldWidgetNode(template.Node):
@@ -193,15 +198,15 @@ def auto_populated_field_script(auto_pop_fields, change = False):
193 198
                      ' var e = document.getElementById("id_%s");' \
194 199
                      ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % (
195 200
                      f, field.name, add_values, field.max_length))
196  
-    return u''.join(t)
  201
+    return mark_safe(u''.join(t))
197 202
 auto_populated_field_script = register.simple_tag(auto_populated_field_script)
198 203
 
199 204
 def filter_interface_script_maybe(bound_field):
200 205
     f = bound_field.field
201 206
     if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface:
202  
-        return u'<script type="text/javascript">addEvent(window, "load", function(e) {' \
  207
+        return mark_safe(u'<script type="text/javascript">addEvent(window, "load", function(e) {' \
203 208
               ' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
204  
-              f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX)
  209
+              f.name, escape(f.verbose_name.replace('"', '\\"')), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX))
205 210
     else:
206 211
         return ''
207 212
 filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe)
3  django/contrib/admin/templatetags/adminapplist.py
... ...
@@ -1,6 +1,7 @@
1 1
 from django import template
2 2
 from django.db.models import get_models
3 3
 from django.utils.encoding import force_unicode
  4
+from django.utils.safestring import mark_safe
4 5
 
5 6
 register = template.Library()
6 7
 
@@ -38,7 +39,7 @@ def render(self, context):
38 39
                         if True in perms.values():
39 40
                             model_list.append({
40 41
                                 'name': force_unicode(capfirst(m._meta.verbose_name_plural)),
41  
-                                'admin_url': u'%s/%s/' % (force_unicode(app_label), m.__name__.lower()),
  42
+                                'admin_url': mark_safe(u'%s/%s/' % (force_unicode(app_label), m.__name__.lower())),
42 43
                                 'perms': perms,
43 44
                             })
44 45
 
3  django/contrib/admin/utils.py
@@ -3,6 +3,7 @@
3 3
 import re
4 4
 from email.Parser import HeaderParser
5 5
 from email.Errors import HeaderParseError
  6
+from django.utils.safestring import mark_safe
6 7
 try:
7 8
     import docutils.core
8 9
     import docutils.nodes
@@ -66,7 +67,7 @@ def parse_rst(text, default_reference_context, thing_being_parsed=None, link_bas
66 67
     parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
67 68
                 destination_path=None, writer_name='html',
68 69
                 settings_overrides=overrides)
69  
-    return parts['fragment']
  70
+    return mark_safe(parts['fragment'])
70 71
 
71 72
 #
72 73
 # reST roles
3  django/contrib/admin/views/decorators.py
@@ -4,6 +4,7 @@
4 4
 from django.contrib.auth import authenticate, login
5 5
 from django.shortcuts import render_to_response
6 6
 from django.utils.translation import ugettext_lazy, ugettext as _
  7
+from django.utils.safestring import mark_safe
7 8
 import base64, datetime, md5
8 9
 import cPickle as pickle
9 10
 
@@ -22,7 +23,7 @@ def _display_login_form(request, error_message=''):
22 23
         post_data = _encode_post_data({})
23 24
     return render_to_response('admin/login.html', {
24 25
         'title': _('Log in'),
25  
-        'app_path': request.path,
  26
+        'app_path': mark_safe(request.path),
26 27
         'post_data': post_data,
27 28
         'error_message': error_message
28 29
     }, context_instance=template.RequestContext(request))
3  django/contrib/admin/views/doc.py
@@ -10,6 +10,7 @@
10 10
 from django.contrib.admin import utils
11 11
 from django.contrib.sites.models import Site
12 12
 from django.utils.translation import ugettext as _
  13
+from django.utils.safestring import mark_safe
13 14
 import inspect, os, re
14 15
 
15 16
 # Exclude methods starting with these strings from documentation
@@ -29,7 +30,7 @@ def bookmarklets(request):
29 30
     # Hack! This couples this view to the URL it lives at.
30 31
     admin_root = request.path[:-len('doc/bookmarklets/')]
31 32
     return render_to_response('admin_doc/bookmarklets.html', {
32  
-        'admin_url': "%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), admin_root),
  33
+        'admin_url': mark_safe("%s://%s%s" % (request.is_secure() and 'https' or 'http', request.get_host(), admin_root)),
33 34
     }, context_instance=RequestContext(request))
34 35
 bookmarklets = staff_member_required(bookmarklets)
35 36
 
29  django/contrib/admin/views/main.py
@@ -14,6 +14,7 @@
14 14
 from django.utils.text import capfirst, get_text_list
15 15
 from django.utils.encoding import force_unicode, smart_str
16 16
 from django.utils.translation import ugettext as _
  17
+from django.utils.safestring import mark_safe
17 18
 import operator
18 19
 
19 20
 try:
@@ -136,7 +137,9 @@ def __init__(self, field, field_mapping, original):
136 137
         self._repr_filled = False
137 138
 
138 139
         if field.rel:
139  
-            self.related_url = u'../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
  140
+            self.related_url = mark_safe(u'../../../%s/%s/'
  141
+                    % (field.rel.to._meta.app_label,
  142
+                        field.rel.to._meta.object_name.lower()))
140 143
 
141 144
     def original_value(self):
142 145
         if self.original:
@@ -216,7 +219,7 @@ def render_change_form(model, manipulator, context, add=False, change=False, for
216 219
         'javascript_imports': get_javascript_imports(opts, auto_populated_fields, field_sets),
217 220
         'ordered_objects': ordered_objects,
218 221
         'inline_related_objects': inline_related_objects,
219  
-        'form_url': form_url,
  222
+        'form_url': mark_safe(form_url),
220 223
         'opts': opts,
221 224
         'content_type_id': ContentType.objects.get_for_model(model).id,
222 225
     }
@@ -436,12 +439,14 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
436 439
                 if related.field.rel.edit_inline or not related.opts.admin:
437 440
                     # Don't display link to edit, because it either has no
438 441
                     # admin or is edited inline.
439  
-                    nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj), []])
  442
+                    nh(deleted_objects, current_depth, [mark_safe(u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj)), []])
440 443
                 else:
441 444
                     # Display a link to the admin page.
442  
-                    nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
443  
-                        (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(),
444  
-                        sub_obj._get_pk_val(), sub_obj), []])
  445
+                    nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="../../../../%s/%s/%s/">%s</a>' %
  446
+                        (escape(force_unicode(capfirst(related.opts.verbose_name))),
  447
+                            related.opts.app_label,
  448
+                            related.opts.object_name.lower(),
  449
+                            sub_obj._get_pk_val(), sub_obj)), []])
445 450
                 _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
446 451
         else:
447 452
             has_related_objs = False
@@ -453,8 +458,8 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
453 458
                     nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), escape(sub_obj)), []])
454 459
                 else:
455 460
                     # Display a link to the admin page.
456  
-                    nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
457  
-                        (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []])
  461
+                    nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
  462
+                        (escape(force_unicode(capfirst(related.opts.verbose_name))), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj))), []])
458 463
                 _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
459 464
             # If there were related objects, and the user doesn't have
460 465
             # permission to delete them, add the missing perm to perms_needed.
@@ -485,9 +490,9 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
485 490
                 else:
486 491
                     # Display a link to the admin page.
487 492
                     nh(deleted_objects, current_depth, [
488  
-                        (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name)}) + \
  493
+                        mark_safe((_('One or more %(fieldname)s in %(name)s:') % {'fieldname': escape(force_unicode(related.field.verbose_name)), 'name': escape(force_unicode(related.opts.verbose_name))}) + \
489 494
                         (u' <a href="../../../../%s/%s/%s/">%s</a>' % \
490  
-                            (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []])
  495
+                            (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj)))), []])
491 496
         # If there were related objects, and the user doesn't have
492 497
         # permission to change them, add the missing perm to perms_needed.
493 498
         if related.opts.admin and has_related_objs:
@@ -507,7 +512,7 @@ def delete_stage(request, app_label, model_name, object_id):
507 512
 
508 513
     # Populate deleted_objects, a data structure of all related objects that
509 514
     # will also be deleted.
510  
-    deleted_objects = [u'%s: <a href="../../%s/">%s</a>' % (force_unicode(capfirst(opts.verbose_name)), force_unicode(object_id), escape(obj)), []]
  515
+    deleted_objects = [mark_safe(u'%s: <a href="../../%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), force_unicode(object_id), escape(obj))), []]
511 516
     perms_needed = set()
512 517
     _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
513 518
 
@@ -604,7 +609,7 @@ def get_query_string(self, new_params=None, remove=None):
604 609
                 del p[k]
605 610
             elif v is not None:
606 611
                 p[k] = v
607  
-        return '?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
  612
+        return mark_safe('?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20'))
608 613
 
609 614
     def get_results(self, request):
610 615
         paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page)
7  django/contrib/csrf/middleware.py
@@ -7,11 +7,12 @@
7 7
 """
8 8
 from django.conf import settings
9 9
 from django.http import HttpResponseForbidden
  10
+from django.utils.safestring import mark_safe
10 11
 import md5
11 12
 import re
12 13
 import itertools
13 14
 
14  
-_ERROR_MSG = '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>'
  15
+_ERROR_MSG = mark_safe('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><body><h1>403 Forbidden</h1><p>Cross Site Request Forgery detected. Request aborted.</p></body></html>')
15 16
 
16 17
 _POST_FORM_RE = \
17 18
     re.compile(r'(<form\W[^>]*\bmethod=(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
@@ -82,10 +83,10 @@ def process_response(self, request, response):
82 83
                                             itertools.repeat(''))
83 84
             def add_csrf_field(match):
84 85
                 """Returns the matched <form> tag plus the added <input> element"""
85  
-                return match.group() + "<div style='display:none;'>" + \
  86
+                return mark_safe(match.group() + "<div style='display:none;'>" + \
86 87
                 "<input type='hidden' " + idattributes.next() + \
87 88
                 " name='csrfmiddlewaretoken' value='" + csrf_token + \
88  
-                "' /></div>"
  89
+                "' /></div>")
89 90
 
90 91
             # Modify any POST forms
91 92
             response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
13  django/contrib/databrowse/datastructures.py
@@ -8,6 +8,7 @@
8 8
 from django.utils.text import capfirst
9 9
 from django.utils.translation import get_date_formats
10 10
 from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
  11
+from django.utils.safestring import mark_safe
11 12
 from django.db.models.query import QuerySet
12 13
 
13 14
 EMPTY_VALUE = '(None)'
@@ -28,7 +29,7 @@ def model_databrowse(self):
28 29
         return self.site.registry[self.model]
29 30
 
30 31
     def url(self):
31  
-        return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
  32
+        return mark_safe('%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name))
32 33
 
33 34
     def objects(self, **kwargs):
34 35
         return self.get_query_set().filter(**kwargs)
@@ -68,9 +69,9 @@ def choices(self):
68 69
 
69 70
     def url(self):
70 71
         if self.field.choices:
71  
-            return '%s%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name)
  72
+            return mark_safe('%s%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name))
72 73
         elif self.field.rel:
73  
-            return '%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name)
  74
+            return mark_safe('%s%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name))
74 75
 
75 76
 class EasyChoice(object):
76 77
     def __init__(self, easy_model, field, value, label):
@@ -81,7 +82,7 @@ def __repr__(self):
81 82
         return smart_str(u'<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
82 83
 
83 84
     def url(self):
84  
-        return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
  85
+        return mark_safe('%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value)))
85 86
 
86 87
 class EasyInstance(object):
87 88
     def __init__(self, easy_model, instance):
@@ -184,14 +185,14 @@ def urls(self):
184 185
             if self.field.rel.to in self.model.model_list:
185 186
                 lst = []
186 187
                 for value in self.values():
187  
-                    url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
  188
+                    url = mark_safe('%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val())))
188 189
                     lst.append((smart_unicode(value), url))
189 190
             else:
190 191
                 lst = [(value, None) for value in self.values()]
191 192
         elif self.field.choices:
192 193
             lst = []
193 194
             for value in self.values():
194  
-                url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
  195
+                url = mark_safe('%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value)))
195 196
                 lst.append((value, url))
196 197
         elif isinstance(self.field, models.URLField):
197 198
             val = self.values()[0]
12  django/contrib/databrowse/plugins/calendars.py
@@ -5,8 +5,9 @@
5 5
 from django.shortcuts import render_to_response
6 6
 from django.utils.text import capfirst
7 7
 from django.utils.translation import get_date_formats
8  
-from django.views.generic import date_based
9 8
 from django.utils.encoding import force_unicode
  9
+from django.utils.safestring import mark_safe
  10
+from django.views.generic import date_based
10 11
 import datetime
11 12
 import time
12 13
 
@@ -29,16 +30,17 @@ def model_index_html(self, request, model, site):
29 30
         fields = self.field_dict(model)
30 31
         if not fields:
31 32
             return u''
32  
-        return u'<p class="filter"><strong>View calendar by:</strong> %s</p>' % \
33  
-            u', '.join(['<a href="calendars/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()])
  33
+        return mark_safe(u'<p class="filter"><strong>View calendar by:</strong> %s</p>' % \
  34
+            u', '.join(['<a href="calendars/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()]))
34 35
 
35 36
     def urls(self, plugin_name, easy_instance_field):
36 37
         if isinstance(easy_instance_field.field, models.DateField):
37  
-            return [u'%s%s/%s/%s/%s/%s/' % (easy_instance_field.model.url(),
  38
+            return [mark_safe(u'%s%s/%s/%s/%s/%s/' % (
  39
+                easy_instance_field.model.url(),
38 40
                 plugin_name, easy_instance_field.field.name,
39 41
                 easy_instance_field.raw_value.year,
40 42
                 easy_instance_field.raw_value.strftime('%b').lower(),
41  
-                easy_instance_field.raw_value.day)]
  43
+                easy_instance_field.raw_value.day))]
42 44
 
43 45
     def model_view(self, request, model_databrowse, url):
44 46
         self.model, self.site = model_databrowse.model, model_databrowse.site
10  django/contrib/databrowse/plugins/fieldchoices.py
@@ -5,6 +5,7 @@
5 5
 from django.shortcuts import render_to_response
6 6
 from django.utils.text import capfirst
7 7
 from django.utils.encoding import smart_str, force_unicode
  8
+from django.utils.safestring import mark_safe
8 9
 from django.views.generic import date_based
9 10
 import datetime
10 11
 import time
@@ -32,15 +33,16 @@ def model_index_html(self, request, model, site):
32 33
         fields = self.field_dict(model)
33 34
         if not fields:
34 35
             return u''
35  
-        return u'<p class="filter"><strong>View by:</strong> %s</p>' % \
36  
-            u', '.join(['<a href="fields/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()])
  36
+        return mark_safe(u'<p class="filter"><strong>View by:</strong> %s</p>' % \
  37
+            u', '.join(['<a href="fields/%s/">%s</a>' % (f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values()]))
37 38
 
38 39
     def urls(self, plugin_name, easy_instance_field):
39 40
         if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
40 41
             field_value = smart_str(easy_instance_field.raw_value)
41  
-            return [u'%s%s/%s/%s/' % (easy_instance_field.model.url(),
  42
+            return [mark_safe(u'%s%s/%s/%s/' % (
  43
+                easy_instance_field.model.url(),
42 44
                 plugin_name, easy_instance_field.field.name,
43  
-                urllib.quote(field_value, safe=''))]
  45
+                urllib.quote(field_value, safe='')))]
44 46
 
45 47
     def model_view(self, request, model_databrowse, url):
46 48
         self.model, self.site = model_databrowse.model, model_databrowse.site
3  django/contrib/databrowse/sites.py
@@ -2,6 +2,7 @@
2 2
 from django.db import models
3 3
 from django.contrib.databrowse.datastructures import EasyModel, EasyChoice
4 4
 from django.shortcuts import render_to_response
  5
+from django.utils.safestring import mark_safe
5 6
 
6 7
 class AlreadyRegistered(Exception):
7 8
     pass
@@ -60,7 +61,7 @@ def root(self, request, url):
60 61
 
61 62
     def main_view(self, request):
62 63
         easy_model = EasyModel(self.site, self.model)
63  
-        html_snippets = u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()])
  64
+        html_snippets = mark_safe(u'\n'.join([p.model_index_html(request, self.model, self.site) for p in self.plugins.values()]))
64 65
         return render_to_response('databrowse/model_detail.html', {
65 66
             'model': easy_model,
66 67
             'root_url': self.site.root_url,
8  django/contrib/flatpages/views.py
@@ -4,6 +4,7 @@
4 4
 from django.http import HttpResponse
5 5
 from django.conf import settings
6 6
 from django.core.xheaders import populate_xheaders
  7
+from django.utils.safestring import mark_safe
7 8
 
8 9
 DEFAULT_TEMPLATE = 'flatpages/default.html'
9 10
 
@@ -30,6 +31,13 @@ def flatpage(request, url):
30 31
         t = loader.select_template((f.template_name, DEFAULT_TEMPLATE))
31 32
     else:
32 33
         t = loader.get_template(DEFAULT_TEMPLATE)
  34
+
  35
+    # To avoid having to always use the "|safe" filter in flatpage templates,
  36
+    # mark the title and content as already safe (since they are raw HTML
  37
+    # content in the first place).
  38
+    f.title = mark_safe(f.title)
  39
+    f.content = mark_safe(f.content)
  40
+
33 41
     c = RequestContext(request, {
34 42
         'flatpage': f,
35 43
     })
4  django/contrib/humanize/templatetags/humanize.py
@@ -21,6 +21,7 @@ def ordinal(value):
21 21
     if value % 100 in (11, 12, 13): # special case
22 22
         return u"%d%s" % (value, t[0])
23 23
     return u'%d%s' % (value, t[value % 10])
  24
+ordinal.is_safe = True
24 25
 register.filter(ordinal)
25 26
 
26 27
 def intcomma(value):
@@ -34,6 +35,7 @@ def intcomma(value):
34 35
         return new
35 36
     else:
36 37
         return intcomma(new)
  38
+intcomma.is_safe = True
37 39
 register.filter(intcomma)
38 40
 
39 41
 def intword(value):
@@ -55,6 +57,7 @@ def intword(value):
55 57
         new_value = value / 1000000000000.0
56 58
         return ungettext('%(value).1f trillion', '%(value).1f trillion', new_value) % {'value': new_value}
57 59
     return value
  60
+intword.is_safe = False
58 61
 register.filter(intword)
59 62
 
60 63
 def apnumber(value):
@@ -69,6 +72,7 @@ def apnumber(value):
69 72
     if not 0 < value < 10:
70 73
         return value
71 74
     return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
  75
+apnumber.is_safe = True
72 76
 register.filter(apnumber)
73 77
 
74 78
 def naturalday(value, arg=None):
10  django/contrib/markup/templatetags/markup.py
@@ -17,6 +17,7 @@
17 17
 from django import template
18 18
 from django.conf import settings
19 19
 from django.utils.encoding import smart_str, force_unicode
  20
+from django.utils.safestring import mark_safe
20 21
 
21 22
 register = template.Library()
22 23
 
@@ -28,7 +29,8 @@ def textile(value):
28 29
             raise template.TemplateSyntaxError, "Error in {% textile %} filter: The Python textile library isn't installed."
29 30
         return force_unicode(value)
30 31
     else:
31  
-        return force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8'))
  32
+        return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8')))
  33
+textile.is_safe = True
32 34
 
33 35
 def markdown(value):
34 36
     try:
@@ -38,7 +40,8 @@ def markdown(value):
38 40
             raise template.TemplateSyntaxError, "Error in {% markdown %} filter: The Python markdown library isn't installed."
39 41
         return force_unicode(value)
40 42
     else:
41  
-        return force_unicode(markdown.markdown(smart_str(value)))
  43
+        return mark_safe(force_unicode(markdown.markdown(smart_str(value))))
  44
+markdown.is_safe = True
42 45
 
43 46
 def restructuredtext(value):
44 47
     try:
@@ -50,7 +53,8 @@ def restructuredtext(value):
50 53
     else:
51 54
         docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
52 55
         parts = publish_parts(source=smart_str(value), writer_name="html4css1", settings_overrides=docutils_settings)
53  
-        return force_unicode(parts["fragment"])
  56
+        return mark_safe(force_unicode(parts["fragment"]))
  57
+restructuredtext.is_safe = True
54 58
 
55 59
 register.filter(textile)
56 60
 register.filter(markdown)
6  django/contrib/markup/tests.py
... ...
@@ -1,9 +1,11 @@
1 1
 # Quick tests for the markup templatetags (django.contrib.markup)
2 2
 
3  
-from django.template import Template, Context, add_to_builtins
4 3
 import re
5 4
 import unittest
6 5
 
  6
+from django.template import Template, Context, add_to_builtins
  7
+from django.utils.html import escape
  8
+
7 9
 add_to_builtins('django.contrib.markup.templatetags.markup')
8 10
 
9 11
 class Templates(unittest.TestCase):
@@ -24,7 +26,7 @@ def test_textile(self):
24 26
 
25 27
 <p>Paragraph 2 with &#8220;quotes&#8221; and <code>code</code></p>""")
26 28
         else:
27  
-            self.assertEqual(rendered, textile_content)
  29
+            self.assertEqual(rendered, escape(textile_content))
28 30
 
29 31
     def test_markdown(self):
30 32
         try:
3  django/contrib/sitemaps/templates/sitemap.xml
... ...
@@ -1,4 +1,4 @@
1  
-<?xml version="1.0" encoding="UTF-8"?>
  1
+{% autoescape off %}<?xml version="1.0" encoding="UTF-8"?>
2 2
 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3 3
 {% spaceless %}
4 4
 {% for url in urlset %}
@@ -11,3 +11,4 @@
11 11
 {% endfor %}
12 12
 {% endspaceless %}
13 13
 </urlset>
  14
+{% endautoescape %}
3  django/contrib/sitemaps/templates/sitemap_index.xml
... ...
@@ -1,4 +1,5 @@
1  
-<?xml version="1.0" encoding="UTF-8"?>
  1
+{% autoescape off %}<?xml version="1.0" encoding="UTF-8"?>
2 2
 <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3 3
 {% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %}
4 4
 </sitemapindex>
  5
+{% endautoescape %}
15  django/newforms/forms.py
@@ -7,6 +7,7 @@
7 7
 from django.utils.datastructures import SortedDict
8 8
 from django.utils.html import escape
9 9
 from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
  10
+from django.utils.safestring import mark_safe
10 11
 
11 12
 from fields import Field
12 13
 from widgets import TextInput, Textarea
@@ -118,7 +119,8 @@ def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_
118 119
                     output.append(error_row % force_unicode(bf_errors))
119 120
                 if bf.label:
120 121
                     label = escape(force_unicode(bf.label))
121  
-                    # Only add the suffix if the label does not end in punctuation.
  122
+                    # Only add the suffix if the label does not end in
  123
+                    # punctuation.
122 124
                     if self.label_suffix:
123 125
                         if label[-1] not in ':?.!':
124 126
                             label += self.label_suffix
@@ -136,11 +138,14 @@ def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_
136 138
             str_hidden = u''.join(hidden_fields)
137 139
             if output:
138 140
                 last_row = output[-1]
139  
-                # Chop off the trailing row_ender (e.g. '</td></tr>') and insert the hidden fields.
  141
+                # Chop off the trailing row_ender (e.g. '</td></tr>') and
  142
+                # insert the hidden fields.
140 143
                 output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
141  
-            else: # If there aren't any rows in the output, just append the hidden fields.
  144
+            else:
  145
+                # If there aren't any rows in the output, just append the
  146
+                # hidden fields.
142 147
                 output.append(str_hidden)
143  
-        return u'\n'.join(output)
  148
+        return mark_safe(u'\n'.join(output))
144 149
 
145 150
     def as_table(self):
146 151
         "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
@@ -303,7 +308,7 @@ def label_tag(self, contents=None, attrs=None):
303 308
         if id_:
304 309
             attrs = attrs and flatatt(attrs) or ''
305 310
             contents = '<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, contents)
306  
-        return contents
  311
+        return mark_safe(contents)
307 312
 
308 313
     def _is_hidden(self):
309 314
         "Returns True if this BoundField's widget is hidden."
8  django/newforms/util.py
... ...
@@ -1,6 +1,7 @@
1 1
 from django.utils.html import escape
2 2
 from django.utils.encoding import smart_unicode, StrAndUnicode, force_unicode
3 3
 from django.utils.functional import Promise
  4
+from django.utils.safestring import mark_safe
4 5
 
5 6
 def flatatt(attrs):
6 7
     """
@@ -22,7 +23,9 @@ def __unicode__(self):
22 23
 
23 24
     def as_ul(self):
24 25
         if not self: return u''
25  
-        return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s%s</li>' % (k, force_unicode(v)) for k, v in self.items()])
  26
+        return mark_safe(u'<ul class="errorlist">%s</ul>'
  27
+                % ''.join([u'<li>%s%s</li>' % (k, force_unicode(v))
  28
+                    for k, v in self.items()]))
26 29
 
27 30
     def as_text(self):
28 31
         return u'\n'.join([u'* %s\n%s' % (k, u'\n'.join([u'  * %s' % force_unicode(i) for i in v])) for k, v in self.items()])
@@ -36,7 +39,8 @@ def __unicode__(self):
36 39
 
37 40
     def as_ul(self):
38 41
         if not self: return u''
39  
-        return u'<ul class="errorlist">%s</ul>' % ''.join([u'<li>%s</li>' % force_unicode(e) for e in self])
  42
+        return mark_safe(u'<ul class="errorlist">%s</ul>'
  43
+                % ''.join([u'<li>%s</li>' % force_unicode(e) for e in self]))
40 44
 
41 45
     def as_text(self):
42 46
         if not self: return u''
40  django/newforms/widgets.py
@@ -14,6 +14,7 @@
14 14
 from django.utils.html import escape
15 15
 from django.utils.translation import ugettext
16 16
 from django.utils.encoding import StrAndUnicode, force_unicode
  17
+from django.utils.safestring import mark_safe
17 18
 from util import flatatt
18 19
 
19 20
 __all__ = (
@@ -86,8 +87,10 @@ class Input(Widget):
86 87
     def render(self, name, value, attrs=None):
87 88
         if value is None: value = ''
88 89
         final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
89  
-        if value != '': final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
90  
-        return u'<input%s />' % flatatt(final_attrs)
  90
+        if value != '':
  91
+            # Only add the 'value' attribute if a value is non-empty.
  92
+            final_attrs['value'] = force_unicode(value)
  93
+        return mark_safe(u'<input%s />' % flatatt(final_attrs))
91 94
 
92 95
 class TextInput(Input):
93 96
     input_type = 'text'
@@ -120,7 +123,9 @@ def __init__(self, attrs=None, choices=()):
120 123
     def render(self, name, value, attrs=None, choices=()):
121 124
         if value is None: value = []
122 125
         final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
123  
-        return u'\n'.join([(u'<input%s />' % flatatt(dict(value=force_unicode(v), **final_attrs))) for v in value])
  126
+        return mark_safe(u'\n'.join([(u'<input%s />' %
  127
+            flatatt(dict(value=force_unicode(v), **final_attrs)))
  128
+            for v in value]))
124 129
 
125 130
     def value_from_datadict(self, data, files, name):
126 131
         if isinstance(data, MultiValueDict):
@@ -149,7 +154,8 @@ def render(self, name, value, attrs=None):
149 154
         if value is None: value = ''
150 155
         value = force_unicode(value)
151 156
         final_attrs = self.build_attrs(attrs, name=name)
152  
-        return u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))
  157
+        return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
  158
+                escape(value)))
153 159
 
154 160
 class DateTimeInput(Input):
155 161
     input_type = 'text'
@@ -183,8 +189,9 @@ def render(self, name, value, attrs=None):
183 189
         if result:
184 190
             final_attrs['checked'] = 'checked'
185 191
         if value not in ('', True, False, None):
186  
-            final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
187  
-        return u'<input%s />' % flatatt(final_attrs)
  192
+            # Only add the 'value' attribute if a value is non-empty.
  193
+            final_attrs['value'] = force_unicode(value)
  194
+        return mark_safe(u'<input%s />' % flatatt(final_attrs))
188 195
 
189 196
     def value_from_datadict(self, data, files, name):
190 197
         if name not in data:
@@ -205,13 +212,14 @@ def render(self, name, value, attrs=None, choices=()):
205 212
         if value is None: value = ''
206 213
         final_attrs = self.build_attrs(attrs, name=name)
207 214
         output = [u'<select%s>' % flatatt(final_attrs)]
208  
-        str_value = force_unicode(value) # Normalize to string.
  215
+        # Normalize to string.
  216
+        str_value = force_unicode(value)
209 217
         for option_value, option_label in chain(self.choices, choices):
210 218
             option_value = force_unicode(option_value)
211 219
             selected_html = (option_value == str_value) and u' selected="selected"' or ''
212 220
             output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
213 221
         output.append(u'</select>')
214  
-        return u'\n'.join(output)
  222
+        return mark_safe(u'\n'.join(output))
215 223
 
216 224
 class NullBooleanSelect(Select):
217 225
     """
@@ -248,7 +256,7 @@ def render(self, name, value, attrs=None, choices=()):
248 256
             selected_html = (option_value in str_values) and ' selected="selected"' or ''
249 257
             output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(force_unicode(option_label))))
250 258
         output.append(u'</select>')
251  
-        return u'\n'.join(output)
  259
+        return mark_safe(u'\n'.join(output))
252 260
 
253 261
     def value_from_datadict(self, data, files, name):
254 262
         if isinstance(data, MultiValueDict):
@@ -269,7 +277,8 @@ def __init__(self, name, value, attrs, choice, index):
269 277
         self.index = index
270 278
 
271 279
     def __unicode__(self):
272  
-        return u'<label>%s %s</label>' % (self.tag(), self.choice_label)
  280
+        return mark_safe(u'<label>%s %s</label>' % (self.tag(),
  281
+                self.choice_label))
273 282
 
274 283
     def is_checked(self):
275 284
         return self.value == self.choice_value
@@ -280,7 +289,7 @@ def tag(self):
280 289
         final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value)
281 290
         if self.is_checked():
282 291
             final_attrs['checked'] = 'checked'
283  
-        return u'<input%s />' % flatatt(final_attrs)
  292
+        return mark_safe(u'<input%s />' % flatatt(final_attrs))
284 293
 
285 294
 class RadioFieldRenderer(StrAndUnicode):
286 295
     """
@@ -304,7 +313,8 @@ def __unicode__(self):
304 313
 
305 314
     def render(self):
306 315
         """Outputs a <ul> for this set of radio fields."""
307  
-        return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self])
  316
+        return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
  317
+                % force_unicode(w) for w in self]))
308 318
 
309 319
 class RadioSelect(Select):
310 320
 
@@ -341,7 +351,8 @@ def render(self, name, value, attrs=None, choices=()):
341 351
         has_id = attrs and 'id' in attrs
342 352
         final_attrs = self.build_attrs(attrs, name=name)
343 353
         output = [u'<ul>']
344  
-        str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
  354
+        # Normalize to strings