Changeset 6671
- Timestamp:
- 11/14/07 06:58:53 (2 years ago)
- Files:
-
- django/trunk/django/contrib/admin/filterspecs.py (modified) (3 diffs)
- django/trunk/django/contrib/admin/models.py (modified) (2 diffs)
- django/trunk/django/contrib/admin/templates/admin/base_site.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/change_form.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/date_hierarchy.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/delete_confirmation.html (modified) (2 diffs)
- django/trunk/django/contrib/admin/templates/admin_doc/model_detail.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/edit_inline_stacked.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/edit_inline_tabular.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/index.html (modified) (2 diffs)
- django/trunk/django/contrib/admin/templates/admin/invalid_setup.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/admin/object_history.html (modified) (2 diffs)
- django/trunk/django/contrib/admin/templates/admin/pagination.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/widget/foreign.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templates/widget/one_to_one.html (modified) (1 diff)
- django/trunk/django/contrib/admin/templatetags/adminapplist.py (modified) (2 diffs)
- django/trunk/django/contrib/admin/templatetags/admin_list.py (modified) (5 diffs)
- django/trunk/django/contrib/admin/templatetags/admin_modify.py (modified) (5 diffs)
- django/trunk/django/contrib/admin/utils.py (modified) (2 diffs)
- django/trunk/django/contrib/admin/views/decorators.py (modified) (2 diffs)
- django/trunk/django/contrib/admin/views/doc.py (modified) (2 diffs)
- django/trunk/django/contrib/admin/views/main.py (modified) (8 diffs)
- django/trunk/django/contrib/csrf/middleware.py (modified) (2 diffs)
- django/trunk/django/contrib/databrowse/datastructures.py (modified) (6 diffs)
- django/trunk/django/contrib/databrowse/plugins/calendars.py (modified) (2 diffs)
- django/trunk/django/contrib/databrowse/plugins/fieldchoices.py (modified) (2 diffs)
- django/trunk/django/contrib/databrowse/sites.py (modified) (2 diffs)
- django/trunk/django/contrib/flatpages/views.py (modified) (2 diffs)
- django/trunk/django/contrib/humanize/templatetags/humanize.py (modified) (4 diffs)
- django/trunk/django/contrib/markup/templatetags/markup.py (modified) (4 diffs)
- django/trunk/django/contrib/markup/tests.py (modified) (2 diffs)
- django/trunk/django/contrib/sitemaps/templates/sitemap_index.xml (modified) (1 diff)
- django/trunk/django/contrib/sitemaps/templates/sitemap.xml (modified) (2 diffs)
- django/trunk/django/newforms/forms.py (modified) (4 diffs)
- django/trunk/django/newforms/util.py (modified) (3 diffs)
- django/trunk/django/newforms/widgets.py (modified) (14 diffs)
- django/trunk/django/oldforms/__init__.py (modified) (13 diffs)
- django/trunk/django/template/context.py (modified) (2 diffs)
- django/trunk/django/template/defaultfilters.py (modified) (48 diffs)
- django/trunk/django/template/defaulttags.py (modified) (4 diffs)
- django/trunk/django/template/__init__.py (modified) (11 diffs)
- django/trunk/django/utils/encoding.py (modified) (2 diffs)
- django/trunk/django/utils/html.py (modified) (5 diffs)
- django/trunk/django/utils/safestring.py (added)
- django/trunk/django/views/debug.py (modified) (14 diffs)
- django/trunk/docs/templates_python.txt (modified) (7 diffs)
- django/trunk/docs/templates.txt (modified) (7 diffs)
- django/trunk/tests/regressiontests/defaultfilters/tests.py (modified) (1 diff)
- django/trunk/tests/regressiontests/forms/forms.py (modified) (1 diff)
- django/trunk/tests/regressiontests/forms/tests.py (modified) (1 diff)
- django/trunk/tests/regressiontests/humanize/tests.py (modified) (2 diffs)
- django/trunk/tests/regressiontests/templates/filters.py (added)
- django/trunk/tests/regressiontests/templates/tests.py (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/filterspecs.py
r5609 r6671 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 … … 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): … … 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): django/trunk/django/contrib/admin/models.py
r5803 r6671 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 … … 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)) django/trunk/django/contrib/admin/templates/admin/base_site.html
r3349 r6671 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 %} django/trunk/django/contrib/admin/templates/admin/change_form.html
r6391 r6671 11 11 <div class="breadcrumbs"> 12 12 <a href="../../../">{% trans "Home" %}</a> › 13 <a href="../">{{ opts.verbose_name_plural|capfirst |escape}}</a> ›14 {% if add %}{% trans "Add" %} {{ opts.verbose_name |escape }}{% else %}{{ original|truncatewords:"18"|escape}}{% endif %}13 <a href="../">{{ opts.verbose_name_plural|capfirst }}</a> › 14 {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %} 15 15 </div> 16 16 {% endif %}{% endblock %} django/trunk/django/contrib/admin/templates/admin/date_hierarchy.html
r3349 r6671 2 2 <div class="xfull"> 3 3 <ul class="toplinks"> 4 {% if back %}<li class="date-back"><a href="{{ back.link }}">‹ {{ back.title |escape}}</a></li>{% endif %}4 {% if back %}<li class="date-back"><a href="{{ back.link }}">‹ {{ 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" /> django/trunk/django/contrib/admin/templates/admin/delete_confirmation.html
r6391 r6671 4 4 <div class="breadcrumbs"> 5 5 <a href="../../../../">{% trans "Home" %}</a> › 6 <a href="../../">{{ opts.verbose_name_plural|capfirst |escape}}</a> ›6 <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> › 7 7 <a href="../">{{ object|escape|truncatewords:"18" }}</a> › 8 8 {% trans 'Delete' %} … … 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> django/trunk/django/contrib/admin/templates/admin_doc/model_detail.html
r6391 r6671 9 9 {% endblock %} 10 10 11 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Models</a> › {{ name |escape}}</div>{% endblock %}11 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Models</a> › {{ 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 django/trunk/django/contrib/admin/templates/admin/edit_inline_stacked.html
r3349 r6671 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}} #{{ forloop.counter }}</h2>4 <h2>{{ bound_related_object.relation.opts.verbose_name|capfirst }} #{{ 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> django/trunk/django/contrib/admin/templates/admin/edit_inline_tabular.html
r3571 r6671 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 %} django/trunk/django/contrib/admin/templates/admin/index.html
r5935 r6671 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 … … 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> django/trunk/django/contrib/admin/templates/admin/invalid_setup.html
r3349 r6671 2 2 {% load i18n %} 3 3 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {{ title |escape}}</div>{% endblock %}4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {{ title }}</div>{% endblock %} 5 5 6 6 {% block content %} django/trunk/django/contrib/admin/templates/admin/object_history.html
r6391 r6671 2 2 {% load i18n %} 3 3 {% block breadcrumbs %} 4 <div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> › <a href="../../">{{ module_name |escape }}</a> › <a href="../">{{ object|escape|truncatewords:"18" }}</a> › {% trans 'History' %}</div>4 <div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> › <a href="../../">{{ module_name }}</a> › <a href="../">{{ object|truncatewords:"18" }}</a> › {% trans 'History' %}</div> 5 5 {% endblock %} 6 6 … … 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 %} django/trunk/django/contrib/admin/templates/admin/pagination.html
r3349 r6671 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 %} <a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %} 11 11 </p> django/trunk/django/contrib/admin/templates/widget/foreign.html
r3352 r6671 16 16 {% endif %} 17 17 {% if bound_field.raw_id_admin %} 18 {% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" |escape}}</strong>{% endif %}18 {% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %} 19 19 {% endif %} 20 20 {% endif %} django/trunk/django/contrib/admin/templates/widget/one_to_one.html
r3352 r6671 1 1 {% if add %}{% include "widget/foreign.html" %}{% endif %} 2 {% if change %}{% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" |escape}}</strong>{% endif %}{% endif %}2 {% if change %}{% if bound_field.existing_display %} <strong>{{ bound_field.existing_display|truncatewords:"14" }}</strong>{% endif %}{% endif %} django/trunk/django/contrib/admin/templatetags/adminapplist.py
r5609 r6671 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() … … 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 }) django/trunk/django/contrib/admin/templatetags/admin_list.py
r5694 r6671 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 … … 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 … … 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): … … 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))198 else: 199 yield (u'<td%s>%s</td>' % (row_class, result_repr))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)) 199 else: 200 yield mark_safe(u'<td%s>%s</td>' % (row_class, conditional_escape(result_repr))) 200 201 201 202 def results(cl): … … 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: django/trunk/django/contrib/admin/templatetags/admin_modify.py
r6399 r6671 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 … … 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 … … 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 … … 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 … … 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 '' django/trunk/django/contrib/admin/utils.py
r4265 r6671 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 … … 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 # django/trunk/django/contrib/admin/views/decorators.py
r5609 r6671 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 … … 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 django/trunk/django/contrib/admin/views/doc.py
r6296 r6671 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 … … 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) django/trunk/django/contrib/admin/views/main.py
r6360 r6671 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 … … 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): … … 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, … … 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: … … 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 … … 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. … … 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) … … 605 610 elif v is not None: 606 611 p[k] = v 607 return '?' + '&'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')612 return mark_safe('?' + '&'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')) 608 613 609 614 def get_results(self, request): django/trunk/django/contrib/csrf/middleware.py
r6038 r6671 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 = \ … … 83 84 def add_csrf_field(match): 84 85 """Returns the matched <form> tag plus the added <input> element""" 85 return ma tch.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 django/trunk/django/contrib/databrowse/datastructures.py
r5947 r6671 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 … … 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): … … 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): … … 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): … … 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: … … 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): django/trunk/django/contrib/databrowse/plugins/calendars.py
r5947 r6671 6 6 from django.utils.text import capfirst 7 7 from django.utils.translation import get_date_formats 8 from django.utils.encoding import force_unicode 9 from django.utils.safestring import mark_safe 8 10 from django.views.generic import date_based 9 from django.utils.encoding import force_unicode10 11 import datetime 11 12 import time … … 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): django/trunk/django/contrib/databrowse/plugins/fieldchoices.py
r5876 r6671 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 … … 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): django/trunk/django/contrib/databrowse/sites.py
r5876 r6671 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): … … 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, django/trunk/django/contrib/flatpages/views.py
r4265 r6671 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' … … 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, django/trunk/django/contrib/humanize/templatetags/humanize.py
r5985 r6671 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 … … 35 36 else: 36 37 return intcomma(new) 38 intcomma.is_safe = True 37 39 register.filter(intcomma) 38 40 … … 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 … … 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 django/trunk/django/contrib/markup/templatetags/markup.py
r5609 r6671 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() … … 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): … … 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): … … 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) django/trunk/django/contrib/markup/tests.py
r5876 r6671 1 1 # Quick tests for the markup templatetags (django.contrib.markup) 2 2 3 from django.template import Template, Context, add_to_builtins4 3 import re 5 4 import unittest 5 6 from django.template import Template, Context, add_to_builtins 7 from django.utils.html import escape 6 8 7 9 add_to_builtins('django.contrib.markup.templatetags.markup') … … 25 27 <p>Paragraph 2 with “quotes” 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): django/trunk/django/contrib/sitemaps/templates/sitemap_index.xml
r4101 r6671 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 %} django/trunk/django/contrib/sitemaps/templates/sitemap.xml
r4088 r6671 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 %} … … 12 12 {% endspaceless %} 13 13 </urlset> 14 {% endautoescape %} django/trunk/django/newforms/forms.py
r6668 r6671 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 … … 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 ':?.!': … … 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): … … 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 contents311 return mark_safe(contents) 307 312 308 313 def _is_hidden(self): django/trunk/django/newforms/util.py
r6625 r6671 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): … … 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): … … 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): django/trunk/django/newforms/widgets.py
r6594 r6671 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 … … 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): … … 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): … … 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): … … 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): … … 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) … … 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): … … 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): … … 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): … … 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): … … 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): … … 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 355 str_values = set([force_unicode(v) for v in value]) 345 356 for i, (option_value, option_label) in enumerate(chain(self.choices, choices)): 346 357 # If an ID attribute was given, add a numeric index as a suffix, … … 353 364 output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(force_unicode(option_label)))) 354 365 output.append(u'</ul>') 355 return u'\n'.join(output)366 return mark_safe(u'\n'.join(output)) 356 367 357 368 def id_for_label(self, id_): … … 451 462 return [value.date(), value.time().replace(microsecond=0)] 452 463 return [None, None] 464 django/trunk/django/oldforms/__init__.py
r6452 r6671 2 2 from django.core.exceptions import PermissionDenied 3 3 from django.utils.html import escape 4 from django.utils.safestring import mark_safe 4 5 from django.conf import settings 5 6 from django.utils.translation import ugettext, ungettext … … 190 191 def html_error_list(self): 191 192 if self.errors(): 192 return '<ul class="errorlist"><li>%s</li></ul>' % '</li><li>'.join([escape(e) for e in self.errors()])193 return mark_safe('<ul class="errorlist"><li>%s</li></ul>' % '</li><li>'.join([escape(e) for e in self.errors()])) 193 194 else: 194 return ''195 return mark_safe('') 195 196 196 197 def get_id(self): … … 227 228 228 229 def html_combined_error_list(self): 229 return ''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')])230 return mark_safe(''.join([field.html_error_list() for field in self.formfield_dict.values() if hasattr(field, 'errors')])) 230 231 231 232 class InlineObjectCollection(object): … … 419 420 if self.max_length: 420 421 max_length = u'maxlength="%s" ' % self.max_length 421 return u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \422 return mark_safe(u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \ 422 423 (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and u' required' or '', 423 self.field_name, self.length, escape(data), max_length) 424 self.field_name, self.length, escape(data), max_length)) 424 425 425 426 def html2python(data): … … 443 444 if data is None: 444 445 data = '' 445 return u'<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \446 return mark_safe(u'<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \ 446 447 (self.get_id(), self.__class__.__name__, self.is_required and u' required' or u'', 447 self.field_name, self.rows, self.cols, escape(data)) 448 self.field_name, self.rows, self.cols, escape(data))) 448 449 449 450 class HiddenField(FormField): … … 454 455 455 456 def render(self, data): 456 return u'<input type="hidden" id="%s" name="%s" value="%s" />' % \457 (self.get_id(), self.field_name, escape(data)) 457 return mark_safe(u'<input type="hidden" id="%s" name="%s" value="%s" />' % \ 458 (self.get_id(), self.field_name, escape(data))) 458 459 459 460 class CheckboxField(FormField): … … 469 470 if data or (data is '' and self.checked_by_default): 470 471 checked_html = ' checked="checked"' 471 return u'<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \472 return mark_safe(u'<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \ 472 473 (self.get_id(), self.__class__.__name__, 473 self.field_name, checked_html) 474 self.field_name, checked_html)) 474 475 475 476 def html2python(data): … … 503 504 output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, force_unicode(escape(display_name)))) 504 505 output.append(u' </select>') 505 return u'\n'.join(output)506 return mark_safe(u'\n'.join(output)) 506 507 507 508 def isValidChoice(self, data, form): … … 557 558 output.extend([u'<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist]) 558 559 output.append(u'</ul>') 559 return u''.join(output)560 return mark_safe(u''.join(output)) 560 561 def __iter__(self): 561 562 for d in self.datalist: … … 572 573 'value': value, 573 574 'name': display_name, 574 'field': u'<input type="radio" id="%s" name="%s" value="%s"%s/>' % \575 (self.get_id() + u'_' + unicode(i), self.field_name, value, selected_html) ,576 'label': u'<label for="%s">%s</label>' % \575 'field': mark_safe(u'<input type="radio" id="%s" name="%s" value="%s"%s/>' % \ 576 (self.get_id() + u'_' + unicode(i), self.field_name, value, selected_html)), 577 'label': mark_safe(u'<label for="%s">%s</label>' % \ 577 578 (self.get_id() + u'_' + unicode(i), display_name), 578 })579 )}) 579 580 return RadioFieldRenderer(datalist, self.ul_class) 580 581 … … 615 616 output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, force_unicode(escape(choice)))) 616 617 output.append(u' </select>') 617 return u'\n'.join(output)618 return mark_safe(u'\n'.join(output)) 618 619 619 620 def isValidChoice(self, field_data, all_data): … … 668 669 self.get_id() + escape(value), choice)) 669 670 output.append(u'</ul>') 670 return u'\n'.join(output)671 return mark_safe(u'\n'.join(output)) 671 672 672 673 #################### … … 689 690 690 691 def render(self, data): 691 return u'<input type="file" id="%s" class="v%s" name="%s" />' % \692 (self.get_id(), self.__class__.__name__, self.field_name) 692 return mark_safe(u'<input type="file" id="%s" class="v%s" name="%s" />' % \ 693 (self.get_id(), self.__class__.__name__, self.field_name)) 693 694 694 695 def html2python(data): django/trunk/django/template/context.py
r6098 r6671 10 10 class Context(object): 11 11 "A stack container for variable context" 12 def __init__(self, dict_=None): 12 13 def __init__(self, dict_=None, autoescape=True): 13 14 dict_ = dict_ or {} 14 15 self.dicts = [dict_] 16 self.autoescape = autoescape 15 17 16 18 def __repr__(self): … … 98 100 for processor in get_standard_processors() + processors: 99 101 self.update(processor(request)) 102 django/trunk/django/template/defaultfilters.py
r6646 r6671 8 8 from django.utils.translation import ugettext, ungettext 9 9 from django.utils.encoding import force_unicode, iri_to_uri 10 from django.utils.safestring import mark_safe, SafeData 10 11 11 12 register = Library() … … 30 31 # arguments by the template parser). 31 32 _dec._decorated_function = getattr(func, '_decorated_function', func) 33 for attr in ('is_safe', 'needs_autoescape'): 34 if hasattr(func, attr): 35 setattr(_dec, attr, getattr(func, attr)) 32 36 return _dec 33 37 … … 40 44 """Adds slashes - useful for passing strings to JavaScript, for example.""" 41 45 return value.replace('\\', '\\\\').replace('"', '\\"').replace("'", "\\'") 46 addslashes.is_safe = True 42 47 addslashes = stringfilter(addslashes) 43 48 … … 45 50 """Capitalizes the first character of the value.""" 46 51 return value and value[0].upper() + value[1:] 52 capfirst.is_safe=True 47 53 capfirst = stringfilter(capfirst) 48 54 … … 51 57 from django.utils.html import fix_ampersands 52 58 return fix_ampersands(value) 59 fix_ampersands.is_safe=True 53 60 fix_ampersands = stringfilter(fix_ampersands) 54 61 … … 91 98 m = f - int(f) 92 99 if not m and d < 0: 93 return u'%d' % int(f)100 return mark_safe(u'%d' % int(f)) 94 101 else: 95 102 formatstr = u'%%.%df' % abs(d) 96 return formatstr % f 103 return mark_safe(formatstr % f) 104 floatformat.is_safe = True 97 105 98 106 def iriencode(value): … … 101 109 iriencode = stringfilter(iriencode) 102 110 103 def linenumbers(value ):111 def linenumbers(value, autoescape=None): 104 112 """Displays text with line numbers.""" 105 113 from django.utils.html import escape 106 114 lines = value.split(u'\n') 107 115 # Find the maximum width of the line count, for use with zero padding 108 # string format command .116 # string format command 109 117 width = unicode(len(unicode(len(lines)))) 110 for i, line in enumerate(lines): 111 lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line)) 112 return u'\n'.join(lines) 118 if not autoescape or isinstance(value, SafeData): 119 for i, line in enumerate(lines): 120 lines[i] = (u"%0" + width + u"d. %s") % (i + 1, line) 121 else: 122 for i, line in enumerate(lines): 123 lines[i] = (u"%0" + width + u"d. %s") % (i + 1, escape(line)) 124 return mark_safe(u'\n'.join(lines)) 125 linenumbers.is_safe = True 126 linenumbers.needs_autoescape = True 113 127 linenumbers = stringfilter(linenumbers) 114 128 … … 116 130 """Converts a string into all lowercase.""" 117 131 return value.lower() 132 lower.is_safe = True 118 133 lower = stringfilter(lower) 119 134 … … 126 141 """ 127 142 return list(value) 143 make_list.is_safe = False 128 144 make_list = stringfilter(make_list) 129 145 … … 136 152 value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') 137 153 value = unicode(re.sub('[^\w\s-]', '', value).strip().lower()) 138 return re.sub('[-\s]+', '-', value) 154 return mark_safe(re.sub('[-\s]+', '-', value)) 155 slugify.is_safe = True 139 156 slugify = stringfilter(slugify) 140 157 … … 153 170 except (ValueError, TypeError): 154 171 return u"" 172 stringformat.is_safe = True 155 173 156 174 def title(value): 157 175 """Converts a string into titlecase.""" 158 176 return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title()) 177 title.is_safe = True 159 178 title = stringfilter(title) 160 179 … … 171 190 return value # Fail silently. 172 191 return truncate_words(value, length) 192 truncatewords.is_safe = True 173 193 truncatewords = stringfilter(truncatewords) 174 194 … … 185 205 return value # Fail silently. 186 206 return truncate_html_words(value, length) 207 truncatewords_html.is_safe = True 187 208 truncatewords_html = stringfilter(truncatewords_html) 188 209 … … 190 211 """Converts a string into all uppercase.""" 191 212 return value.upper() 213 upper.is_safe = False 192 214 upper = stringfilter(upper) 193 215 … … 196 218 from django.utils.http import urlquote 197 219 return urlquote(value) 220 urlencode.is_safe = False 198 221 urlencode = stringfilter(urlencode) 199 222 200 def urlize(value ):223 def urlize(value, autoescape=None): 201 224 """Converts URLs in plain text into clickable links.""" 202 225 from django.utils.html import urlize 203 return urlize(value, nofollow=True) 226 return mark_safe(urlize(value, nofollow=True, autoescape=autoescape)) 227 urlize.is_safe=True 228 urlize.needs_autoescape = True 204 229 urlize = stringfilter(urlize) 205 230 … … 212 237 """ 213 238 from django.utils.html import urlize 214 return urlize(value, trim_url_limit=int(limit), nofollow=True) 239 return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True)) 240 urlizetrunc.is_safe = True 215 241 urlizetrunc = stringfilter(urlizetrunc) 216 242 … … 218 244 """Returns the number of words.""" 219 245 return len(value.split()) 246 wordcount.is_safe = False 220 247 wordcount = stringfilter(wordcount) 221 248 … … 228 255 from django.utils.text import wrap 229 256 return wrap(value, int(arg)) 257 wordwrap.is_safe = True 230 258 wordwrap = stringfilter(wordwrap) 231 259 … … 237 265 """ 238 266 return value.ljust(int(arg)) 267 ljust.is_safe = True 239 268 ljust = stringfilter(ljust) 240 269 … … 246 275 """ 247 276 return value.rjust(int(arg)) 277 rjust.is_safe = True 248 278 rjust = stringfilter(rjust) 249 279 … … 251 281 """Centers the value in a field of a given width.""" 252 282 return value.center(int(arg)) 283 center.is_safe = True 253 284 center = stringfilter(center) 254 285 255 286 def cut(value, arg): 256 """Removes all values of arg from the given string.""" 257 return value.replace(arg, u'') 287 """ 288 Removes all values of arg from the given string. 289 """ 290 safe = isinstance(value, SafeData) 291 value = value.replace(arg, u'') 292 if safe and arg != ';': 293 return mark_safe(value) 294 return value 258 295 cut = stringfilter(cut) 259 296 … … 263 300 264 301 def escape(value): 265 "Escapes a string's HTML" 302 """ 303 Marks the value as a string that should not be auto-escaped. 304 """ 305 from django.utils.safestring import mark_for_escaping 306 return mark_for_escaping(value) 307 escape.is_safe = True 308 escape = stringfilter(escape) 309 310 def force_escape(value): 311 """ 312 Escapes a string's HTML. This returns a new string containing the escaped 313 characters (as opposed to "escape", which marks the content for later 314 possible escaping). 315 """ 266 316 from django.utils.html import escape 267 return escape(value)317 return mark_safe(escape(value)) 268 318 escape = stringfilter(escape) 269 270 def linebreaks(value): 319 force_escape.is_safe = True 320 321 def linebreaks(value, autoescape=None): 271 322 """ 272 323 Replaces line breaks in plain text with appropriate HTML; a single … … 275 326 """ 276 327 from django.utils.html import linebreaks 277 return linebreaks(value) 328 autoescape = autoescape and not isinstance(value, SafeData) 329 return mark_safe(linebreaks(value, autoescape)) 330 linebreaks.is_safe = True 331 linebreaks.needs_autoescape = True 278 332 linebreaks = stringfilter(linebreaks) 279 333 280 def linebreaksbr(value ):334 def linebreaksbr(value, autoescape=None): 281 335 """ 282 336 Converts all newlines in a piece of plain text to HTML line breaks 283 337 (``<br />``). 284 338 """ 285 return value.replace('\n', '<br />') 339 if autoescape and not isinstance(value, SafeData): 340 from django.utils.html import escape 341 value = escape(value) 342 return mark_safe(value.replace('\n', '<br />')) 343 linebreaksbr.is_safe = True 344 linebreaksbr.needs_autoescape = True 286 345 linebreaksbr = stringfilter(linebreaksbr) 346 347 def safe(value): 348 """ 349 Marks the value as a string that should not be auto-escaped. 350 """ 351 from django.utils.safestring import mark_safe 352 return mark_safe(value) 353 safe.is_safe = True 354 safe = stringfilter(safe) 287 355 288 356 def removetags(value, tags): … … 295 363 value = endtag_re.sub(u'', value) 296 364 return value 365 removetags.is_safe = True 297 366 removetags = stringfilter(removetags) 298 367 … … 301 370 from django.utils.html import strip_tags 302 371 return strip_tags(value) 372 striptags.is_safe = True 303 373 striptags = stringfilter(striptags) 304 374 … … 316 386 decorated.sort() 317 387 return [item[1] for item in decorated] 388 dictsort.is_safe = False 318 389 319 390 def dictsortreversed(value, arg): … … 327 398 decorated.reverse() 328 399 return [item[1] for item in decorated] 400 dictsortreversed.is_safe = False 329 401 330 402 def first(value): … … 334 406 except IndexError: 335 407 return u'' 408 first.is_safe = True 336 409 337 410 def join(value, arg): 338 411 """Joins a list with a string, like Python's ``str.join(list)``.""" 339 412 try: 340 returnarg.join(map(force_unicode, value))413 data = arg.join(map(force_unicode, value)) 341 414 except AttributeError: # fail silently but nicely 342 415 return value 416 safe_args = reduce(lambda lhs, rhs: lhs and isinstance(rhs, SafeData), 417 value, True) 418 if safe_args: 419 return mark_safe(data) 420 else: 421 return data 422 join.is_safe = True 343 423 344 424 def length(value): 345 425 """Returns the length of the value - useful for lists.""" 346 426 return len(value) 427 length.is_safe = True 347 428 348 429 def length_is(value, arg): 349 430 """Returns a boolean of whether the value's length is the argument.""" 350 431 return len(value) == int(arg) 432 length_is.is_safe = True 351 433 352 434 def random(value): 353 435 """Returns a random item from the list.""" 354 436 return random_module.choice(value) 437 random.is_safe = True 355 438 356 439 def slice_(value, arg): … … 373 456 except (ValueError, TypeError): 374 457 return value # Fail silently. 375 376 def unordered_list(value): 458 slice_.is_safe = True 459 460 def unordered_list(value, autoescape=None): 377 461 """ 378 462 Recursively takes a self-nested list and returns an HTML unordered list -- … … 395 479 </li> 396 480 """ 481 if autoescape: 482 from django.utils.html import conditional_escape 483 escaper = conditional_escape 484 else: 485 escaper = lambda x: x 397 486 def convert_old_style_list(list_): 398 487 """ … … 444 533 sublist = '\n%s<ul>\n%s\n%s</ul>\n%s' % (indent, sublist, 445 534 indent, indent) 446 output.append('%s<li>%s%s</li>' % (indent, force_unicode(title),447 sublist))535 output.append('%s<li>%s%s</li>' % (indent, 536 escaper(force_unicode(title)), sublist)) 448 537 i += 1 449 538 return '\n'.join(output) 450 539 value, converted = convert_old_style_list(value) 451 return _helper(value) 540 return mark_safe(_helper(value)) 541 unordered_list.is_safe = True 542 unordered_list.needs_autoescape = True 452 543 453 544 ################### … … 458 549 """Adds the arg to the value.""" 459 550 return int(value) + int(arg) 551 add.is_safe = False 460 552 461 553 def get_digit(value, arg): … … 477 569 except IndexError: 478 570 return 0 571 get_digit.is_safe = False 479 572 480 573 ################### … … 490 583 arg = settings.DATE_FORMAT 491 584 return format(value, arg) 585 date.is_safe = False 492 586 493 587 def time(value, arg=None): … … 499 593 arg = settings.TIME_FORMAT 500 594 return time_format(value, arg) 595 time.is_safe = False 501 596 502 597 def timesince(value, arg=None): … … 508 603 return timesince(arg, value) 509 604 return timesince(value) 605 timesince.is_safe = False 510 606 511 607 def timeuntil(value, arg=None): … … 518 614 return timesince(arg, value) 519 615 return timesince(datetime.now(), value) 616 timeuntil.is_safe = False 520 617 521 618 ################### … … 526 623 """If value is unavailable, use given default.""" 527 624 return value or arg 625 default.is_safe = False 528 626 529 627 def default_if_none(value, arg): … … 532 630 return arg 533 631 return value 632 default_if_none.is_safe = False 534 633 535 634 def divisibleby(value, arg): 536 635 """Returns True if the value is devisible by the argument.""" 537 636 return int(value) % int(arg) == 0 637 divisibleby.is_safe = False 538 638 539 639 def yesno(value, arg=None): … … 567 667 return yes 568 668 return no 669 yesno.is_safe = False 569 670 570 671 ################### … … 589 690 return ugettext("%.1f MB") % (bytes / (1024 * 1024)) 590 691 return ugettext("%.1f GB") % (bytes / (1024 * 1024 * 1024)) 692 filesizeformat.is_safe = True 591 693 592 694 def pluralize(value, arg=u's'): … … 595 697 the suffix: 596 698 597 * If value is 0, vote{{ value|plur lize }} displays "0 votes".598 * If value is 1, vote{{ value|plur lize }} displays "1 vote".599 * If value is 2, vote{{ value|plur lize }} displays "2 votes".699 * If value is 0, vote{{ value|pluralize }} displays "0 votes". 700 * If value is 1, vote{{ value|pluralize }} displays "1 vote". 701 * If value is 2, vote{{ value|pluralize }} displays "2 votes". 600 702 601 703 If an argument is provided, that string is used instead: 602 704 603 * If value is 0, class{{ value|plur lize:"es" }} displays "0 classes".604 * If value is 1, class{{ value|plur lize:"es" }} displays "1 class".605 * If value is 2, class{{ value|plur lize:"es" }} displays "2 classes".705 * If value is 0, class{{ value|pluralize:"es" }} displays "0 classes". 706 * If value is 1, class{{ value|pluralize:"es" }} displays "1 class". 707 * If value is 2, class{{ value|pluralize:"es" }} displays "2 classes". 606 708 607 709 If the provided argument contains a comma, the text before the comma is … … 609 711 plural case: 610 712 611 * If value is 0, cand{{ value|plur lize:"y,ies" }} displays "0 candies".612 * If value is 1, cand{{ value|plur lize:"y,ies" }} displays "1 candy".613 * If value is 2, cand{{ value|plur lize:"y,ies" }} displays "2 candies".713 * If value is 0, cand{{ value|pluralize:"y,ies" }} displays "0 candies". 714 * If value is 1, cand{{ value|pluralize:"y,ies" }} displays "1 candy". 715 * If value is 2, cand{{ value|pluralize:"y,ies" }} displays "2 candies". 614 716 """ 615 717 if not u',' in arg: … … 632 734 pass 633 735 return singular_suffix 736 pluralize.is_safe = False 634 737 635 738 def phone2numeric(value): … … 637 740 from django.utils.text import phone2numeric 638 741 return phone2numeric(value) 742 phone2numeric.is_safe = True 639 743 640 744 def pprint(value): … … 645 749 except Exception, e: 646 750 return u"Error in formatting: %s" % force_unicode(e, errors="replace") 751 pprint.is_safe = True 647 752 648 753 # Syntax: register.filter(name of filter, callback) … … 663 768 register.filter(fix_ampersands) 664 769 register.filter(floatformat) 770 register.filter(force_escape) 665 771 register.filter(get_digit) 666 772 register.filter(iriencode) … … 680 786 register.filter(random) 681 787 register.filter(rjust) 788 register.filter(safe) 682 789 register.filter('slice', slice_) 683 790 register.filter(slugify) django/trunk/django/template/defaulttags.py
r6641 r6671 15 15 from django.utils.encoding import smart_str, smart_unicode 16 16 from django.utils.itercompat import groupby 17 from django.utils.safestring import mark_safe 17 18 18 19 register = Library() 20 21 class AutoEscapeControlNode(Node): 22 """Implements the actions of the autoescape tag.""" 23 def __init__(self, setting, nodelist): 24 self.setting, self.nodelist = setting, nodelist 25 26 def render(self, context): 27 old_setting = context.autoescape 28 context.autoescape = self.setting 29 output = self.nodelist.render(context) 30 context.autoescape = old_setting 31 if self.setting: 32 return mark_safe(output) 33 else: 34 return output 19 35 20 36 class CommentNode(Node): … … 394 410 395 411 #@register.tag 412 def autoescape(parser, token): 413 """ 414 Force autoescape behaviour for this block. 415 """ 416 args = token.contents.split() 417 if len(args) != 2: 418 raise TemplateSyntaxError("'Autoescape' tag requires exactly one argument.") 419 arg = args[1] 420 if arg not in (u'on', u'off'): 421 raise TemplateSyntaxError("'Autoescape' argument should be 'on' or 'off'") 422 nodelist = parser.parse(('endautoescape',)) 423 parser.delete_first_token() 424 return AutoEscapeControlNode((arg == 'on'), nodelist) 425 autoescape = register.tag(autoescape) 426 427 #@register.tag 396 428 def comment(parser, token): 397 429 """ … … 493 525 Sample usage:: 494 526 495 {% filter escape|lower %}527 {% filter force_escape|lower %} 496 528 This text will be HTML-escaped, and will appear in lowercase. 497 529 {% endfilter %} … … 499 531 _, rest = token.contents.split(None, 1) 500 532 filter_expr = parser.compile_filter("var|%s" % (rest)) 533 for func, unused in filter_expr.filters: 534 if getattr(func, '_decorated_function', func).__name__ in ('escape', 'safe'): 535 raise TemplateSyntaxError('"filter %s" is not permitted. Use the "autoescape" tag instead.' % func.__name__) 501 536 nodelist = parser.parse(('endfilter',)) 502 537 parser.delete_first_token() django/trunk/django/template/__init__.py
r6399 r6671 58 58 from django.utils.encoding import smart_unicode, force_unicode 59 59 from django.utils.translation import ugettext as _ 60 from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping 61 from django.utils.html import escape 60 62 61 63 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string') … … 596 598 else: 597 599 arg_vals.append(arg.resolve(context)) 598 obj = func(obj, *arg_vals) 600 if getattr(func, 'needs_autoescape', False): 601 new_obj = func(obj, autoescape=context.autoescape, *arg_vals) 602 else: 603 new_obj = func(obj, *arg_vals) 604 if getattr(func, 'is_safe', False) and isinstance(obj, SafeData): 605 obj = mark_safe(new_obj) 606 elif isinstance(obj, EscapeData): 607 obj = mark_for_escaping(new_obj) 608 else: 609 obj = new_obj 599 610 return obj 600 611 … … 638 649 Returns the resolved variable, which may contain attribute syntax, within 639 650 the given context. 640 651 641 652 Deprecated; use the Variable class instead. 642 653 """ … … 648 659 a hard-coded string (if it begins and ends with single or double quote 649 660 marks):: 650 661 651 662 >>> c = {'article': {'section':'News'}} 652 663 >>> Variable('article.section').resolve(c) … … 663 674 (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 664 675 """ 665 676 666 677 def __init__(self, var): 667 678 self.var = var 668 679 self.literal = None 669 680 self.lookups = None 670 681 671 682 try: 672 683 # First try to treat this variable as a number. 673 684 # 674 # Note that this could cause an OverflowError here that we're not 685 # Note that this could cause an OverflowError here that we're not 675 686 # catching. Since this should only happen at compile time, that's 676 687 # probably OK. 677 688 self.literal = float(var) 678 689 679 690 # So it's a float... is it an int? If the original value contained a 680 691 # dot or an "e" then it was a float, not an int. 681 692 if '.' not in var and 'e' not in var.lower(): 682 693 self.literal = int(self.literal) 683 694 684 695 # "2." is invalid 685 696 if var.endswith('.'): … … 692 703 if var[0] in "\"'" and var[0] == var[-1]: 693 704 self.literal = var[1:-1] 694 705 695 706 else: 696 707 # Otherwise we'll set self.lookups so that resolve() knows we're 697 708 # dealing with a bonafide variable 698 709 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR)) 699 710 700 711 def resolve(self, context): 701 712 """Resolve this variable against a given context.""" … … 706 717 # We're dealing with a literal, so it's already been "resolved" 707 718 return self.literal 708 719 709 720 def __repr__(self): 710 721 return "<%s: %r>" % (self.__class__.__name__, self.var) 711 722 712 723 def __str__(self): 713 724 return self.var … … 716 727 """ 717 728 Performs resolution of a real variable (i.e. not a literal) against the 718 given context. 719 729 given context. 730 720 731 As indicated by the method's name, this method is an implementation 721 732 detail and shouldn't be called by external code. Use Variable.resolve() … … 758 769 else: 759 770 raise 760 761 if isinstance(current, (basestring, Promise)): 762 try: 763 current = force_unicode(current) 764 except UnicodeDecodeError: 765 # Failing to convert to unicode can happen sometimes (e.g. debug 766 # tracebacks). So we allow it in this particular instance. 767 pass 771 768 772 return current 769 773 … … 839 843 840 844 def render(self, context): 841 return self.filter_expression.resolve(context) 845 try: 846 output = force_unicode(self.filter_expression.resolve(context)) 847 except UnicodeDecodeError: 848 # Unicode conversion can fail sometimes for reasons out of our 849 # control (e.g. exception rendering). In that case, we fail quietly. 850 return '' 851 if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData): 852 return force_unicode(escape(output)) 853 else: 854 return force_unicode(output) 842 855 843 856 class DebugVariableNode(VariableNode): 844 857 def render(self, context): 845 858 try: 846 return self.filter_expression.resolve(context)859 output = force_unicode(self.filter_expression.resolve(context)) 847 860 except TemplateSyntaxError, e: 848 861 if not hasattr(e, 'source'): 849 862 e.source = self.source 850 863 raise 864 except UnicodeDecodeError: 865 return '' 866 if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData): 867 return escape(output) 868 else: 869 return output 851 870 852 871 def generic_tag_compiler(params, defaults, name, node_class, parser, token): … … 962 981 t = get_template(file_name) 963 982 self.nodelist = t.nodelist 964 return self.nodelist.render(context_class(dict)) 983 return self.nodelist.render(context_class(dict, 984 autoescape=context.autoescape)) 965 985 966 986 compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode) django/trunk/django/utils/encoding.py
r6649 r6671 4 4 5 5 from django.utils.functional import Promise 6 from django.utils.safestring import SafeData, mark_safe 6 7 7 8 class DjangoUnicodeDecodeError(UnicodeDecodeError): … … 52 53 s = unicode(str(s), encoding, errors) 53 54 elif not isinstance(s, unicode): 54 s = unicode(s, encoding, errors) 55 # Note: We use .decode() here, instead of unicode(s, encoding, 56 # errors), so that if s is a SafeString, it ends up being a 57 # SafeUnicode at the end. 58 s = s.decode(encoding, errors) 55 59 except UnicodeDecodeError, e: 56 60 raise DjangoUnicodeDecodeError(s, *e.args) django/trunk/django/utils/html.py
r5717 r6671 4 4 import string 5 5 6 from django.utils.safestring import SafeData, mark_safe 6 7 from django.utils.encoding import force_unicode 7 8 from django.utils.functional import allow_lazy … … 28 29 def escape(html): 29 30 "Return the given HTML with ampersands, quotes and carets encoded." 30 return force_unicode(html).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''')31 return mark_safe(force_unicode(html).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''')) 31 32 escape = allow_lazy(escape, unicode) 32 33 33 def linebreaks(value): 34 "Convert newlines into <p> and <br />s." 34 def conditional_escape(html): 35 """ 36 Similar to escape(), except that it doesn't operate on pre-escaped strings. 37 """ 38 if isinstance(html, SafeData): 39 return html 40 else: 41 return escape(html) 42 43 def linebreaks(value, autoescape=False): 44 "Converts newlines into <p> and <br />s" 35 45 value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines 36 46 paras = re.split('\n{2,}', value) 37 paras = [u'<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras] 47 if autoescape: 48 paras = [u'<p>%s</p>' % escape(p.strip()).replace('\n', '<br />') for p in paras] 49 else: 50 paras = [u'<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras] 38 51 return u'\n\n'.join(paras) 39 linebreaks = allow_lazy(linebreaks, unicode) 52 linebreaks = allow_lazy(linebreaks, unicode) 40 53 41 54 def strip_tags(value): … … 59 72 fix_ampersands = allow_lazy(fix_ampersands, unicode) 60 73 61 def urlize(text, trim_url_limit=None, nofollow=False ):74 def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): 62 75 """ 63 76 Convert any URLs in text into clickable links. … … 73 86 attribute. 74 87 """ 75 trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x 88 if autoescape: 89 trim_url = lambda x, limit=trim_url_limit: conditional_escape(limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x) 90 else: 91 trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x 92 safe_input = isinstance(text, SafeData) 76 93 words = word_split_re.split(force_unicode(text)) 77 94 nofollow_attr = nofollow and ' rel="nofollow"' or '' … … 80 97 if match: 81 98 lead, middle, trail = match.groups() 99 if safe_input: 100 middle = mark_safe(middle) 82 101 if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \ 83 102 len(middle) > 0 and middle[0] in string.letters + string.digits and \ django/trunk/django/views/debug.py
r6585 r6671 334 334 </head> 335 335 <body> 336 337 336 <div id="summary"> 338 337 <h1>{{ exception_type }} at {{ request.path|escape }}</h1> … … 396 395 <h2>Template error</h2> 397 396 <p>In template <code>{{ template_info.name }}</code>, error at line <strong>{{ template_info.line }}</strong></p> 398 <h3>{{ template_info.message |escape}}</h3>397 <h3>{{ template_info.message }}</h3> 399 398 <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}"> 400 399 {% for source_line in template_info.source_lines %} … … 414 413 <div class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></div> 415 414 <br/> 415 {% autoescape off %} 416 416 <div id="browserTraceback"> 417 417 <ul class="traceback"> … … 423 423 <div class="context" id="c{{ frame.id }}"> 424 424 {% if frame.pre_context %} 425 <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line |escape}}</li>{% endfor %}</ol>425 <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol> 426 426 {% endif %} 427 <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line |escape}} <span>...</span></li></ol>427 <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line }} <span>...</span></li></ol> 428 428 {% if frame.post_context %} 429 <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line |escape}}</li>{% endfor %}</ol>429 <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol> 430 430 {% endif %} 431 431 </div> … … 447 447 <tr> 448 448 <td>{{ var.0 }}</td> 449 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>449 <td class="code"><div>{{ var.1|pprint }}</div></td> 450 450 </tr> 451 451 {% endfor %} … … 467 467 File "{{ frame.filename }}" in {{ frame.function }}<br/> 468 468 {% if frame.context_line %} 469 {{ frame.lineno }}. {{ frame.context_line |escape}}<br/>469 {{ frame.lineno }}. {{ frame.context_line }}<br/> 470 470 {% endif %} 471 471 {% endfor %}<br/> … … 477 477 </table> 478 478 </div> 479 {% endautoescape %} 479 480 </div> 480 481 … … 495 496 <tr> 496 497 <td>{{ var.0 }}</td> 497 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>498 <td class="code"><div>{{ var.1|pprint }}</div></td> 498 499 </tr> 499 500 {% endfor %} … … 517 518 <tr> 518 519 <td>{{ var.0 }}</td> 519 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>520 <td class="code"><div>{{ var.1|pprint }}</div></td> 520 521 </tr> 521 522 {% endfor %} … … 539 540 <tr> 540 541 <td>{{ var.0 }}</td> 541 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>542 <td class="code"><div>{{ var.1|pprint }}</div></td> 542 543 </tr> 543 544 {% endfor %} … … 560 561 <tr> 561 562 <td>{{ var.0 }}</td> 562 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>563 <td class="code"><div>{{ var.1|pprint }}</div></td> 563 564 </tr> 564 565 {% endfor %} … … 579 580 <tr> 580 581 <td>{{ var.0 }}</td> 581 <td class="code"><div>{{ var.1|pprint |escape}}</div></td>582 <td class="code"><div>{{ var.1|pprint }}</div></td> 582 583 </tr> 583 584 {% endfor %} … … 594 595 </p> 595 596 </div> 596 597 597 </body> 598 598 </html> … … 646 646 <ol> 647 647 {% for pattern in urlpatterns %} 648 <li>{{ pattern |escape}}</li>648 <li>{{ pattern }}</li> 649 649 {% endfor %} 650 650 </ol> 651 651 <p>The current URL, <code>{{ request_path|escape }}</code>, didn't match any of these.</p> 652 652 {% else %} 653 <p>{{ reason |escape}}</p>653 <p>{{ reason }}</p> 654 654 {% endif %} 655 655 </div> django/trunk/docs/templates_python.txt
r6462 r6671 220 220 While ``TEMPLATE_STRING_IF_INVALID`` can be a useful debugging tool, 221 221 it is a bad idea to turn it on as a 'development default'. 222 222 223 223 Many templates, including those in the Admin site, rely upon the 224 224 silence of the template system when a non-existent variable is … … 226 226 ``TEMPLATE_STRING_IF_INVALID``, you will experience rendering 227 227 problems with these templates and sites. 228 228 229 229 Generally, ``TEMPLATE_STRING_IF_INVALID`` should only be enabled 230 230 in order to debug a specific template problem, then cleared … … 723 723 will use the function's name as the filter name. 724 724 725 Filters and auto-escaping 726 ~~~~~~~~~~~~~~~~~~~~~~~~~ 727 728 **New in Django development version** 729 730 When you are writing a custom filter, you need to give some thought to how 731 this filter will interact with Django's auto-escaping behaviour. Firstly, you 732 should realise that there are three types of strings that can be passed around 733 inside the template code: 734 735 * raw strings are the native Python ``str`` or ``unicode`` types. On 736 output, they are escaped if auto-escaping is in effect and presented 737 unchanged, otherwise. 738 739 * "safe" strings are strings that are safe from further escaping at output 740 time. Any necessary escaping has already been done. They are commonly used 741 for output that contains raw HTML that is intended to be intrepreted on the 742 client side. 743 744 Internally, these strings are of type ``SafeString`` or ``SafeUnicode``, 745 although they share a common base class in ``SafeData``, so you can test 746 for them using code like:: 747 748 if isinstance(value, SafeData): 749 # Do something with the "safe" string. 750 751 * strings which are marked as "needing escaping" are *always* escaped on 752 output, regardless of whether they are in an ``autoescape`` block or not. 753 These strings are only escaped once, however, even if auto-escaping 754 applies. This type of string is internally represented by the types 755 ``EscapeString`` and ``EscapeUnicode``. You will not normally need to worry 756 about these; they exist for the implementation of the ``escape`` filter. 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:: 773 774 @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. 813 725 814 Writing custom template tags 726 815 ---------------------------- … … 841 930 without having to be parsed multiple times. 842 931 932 Auto-escaping considerations 933 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 934 935 The output from template tags is not automatically run through the 936 auto-escaping filters. However, there are still a couple of things you should 937 keep in mind when writing a template tag: 938 939 If the ``render()`` function of your template stores the result in a context 940 variable (rather than returning the result in a string), it should take care 941 to call ``mark_safe()`` if appropriate. When the variable is ultimately 942 rendered, it will be affected by the auto-escape setting in effect at the 943 time, so content that should be safe from further escaping needs to be marked 944 as such. 945 946 Also, if your template tag creates a new context for performing some 947 sub-rendering, you should be careful to set the auto-escape attribute to the 948 current context's value. The ``__init__`` method for the ``Context`` class 949 takes a parameter called ``autoescape`` that you can use for this purpose. For 950 example:: 951 952 def render(self, context): 953 # ... 954 new_context = Context({'var': obj}, autoescape=context.autoescape) 955 # ... Do something with new_context ... 956 957 This is not a very common situation, but it is sometimes useful, particularly 958 if you are rendering a template yourself. For example:: 959 960 def render(self, context): 961 t = template.load_template('small_fragment.html') 962 return t.render(Context({'var': obj}, autoescape=context.autoescape)) 963 964 If we had neglected to pass in the current ``context.autoescape`` value to our 965 new ``Context`` in this example, the results would have *always* been 966 automatically escaped, which may not be the desired behaviour if the template 967 tag is used inside a ``{% autoescape off %}`` block. 968 843 969 Registering the tag 844 970 ~~~~~~~~~~~~~~~~~~~ … … 918 1044 self.date_to_be_formatted = date_to_be_formatted 919 1045 self.format_string = format_string 920 1046 921 1047 def render(self, context): 922 1048 try: … … 935 1061 in favor of a new ``template.Variable`` class. Using this class will usually 936 1062 be more efficient than calling ``template.resolve_variable`` 937 1063 938 1064 To use the ``Variable`` class, simply instantiate it with the name of the 939 1065 variable to be resolved, and then call ``variable.resolve(context)``. So, 940 1066 in the development version, the above example would be more correctly 941 1067 written as: 942 1068 943 1069 .. parsed-literal:: 944 1070 945 1071 class FormatTimeNode(template.Node): 946 1072 def __init__(self, date_to_be_formatted, format_string): 947 1073 self.date_to_be_formatted = **Variable(date_to_be_formatted)** 948 1074 self.format_string = format_string 949 1075 950 1076 def render(self, context): 951 1077 try: … … 954 1080 except template.VariableDoesNotExist: 955 1081 return '' 956 1082 957 1083 Changes are highlighted in bold. 958 1084 django/trunk/docs/templates.txt
r6648 r6671 300 300 wouldn't know which one of the blocks' content to use. 301 301 302 Automatic HTML escaping 303 ======================= 304 305 **New in Django development version** 306 307 A very real problem when creating HTML (and other) output using templates and 308 variable substitution is the possibility of accidently inserting some variable 309 value that affects the resulting HTML. For example, a template fragment such as 310 :: 311 312 Hello, {{ name }}. 313 314 seems like a harmless way to display the user's name. However, if you are 315 displaying data that the user entered directly and they had entered their name as :: 316 317 <script>alert('hello')</script> 318 319 this would always display a Javascript alert box when the page was loaded. 320 Similarly, if you were displaying some data generated by another process and it 321 contained a '<' symbol, you couldn't just dump this straight into your HTML, 322 because it would be treated as the start of an element. The effects of these 323 sorts of problems can vary from merely annoying to allowing exploits via `Cross 324 Site Scripting`_ (XSS) attacks. 325 326 .. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting 327 328 In order to provide some protection against these problems, Django 329 provides automatic (but controllable) HTML escaping for data coming from 330 tempate variables. Inside this tag, any data that comes from template 331 variables is examined to see if it contains one of the five HTML characters 332 (<, >, ', " and &) that often need escaping and those characters are converted 333 to their respective HTML entities. It causes no harm if a character is 334 converted to an entity when it doesn't need to be, so all five characters are 335 always converted. 336 337 Since some variables will contain data that is *intended* to be rendered 338 as HTML, template tag and filter writers can mark their output strings as 339 requiring no further escaping. For example, the ``unordered_list`` filter is 340 designed to return raw HTML and we want the template processor to simply 341 display the results as returned, without applying any escaping. That is taken 342 care of by the filter. The template author need do nothing special in that 343 case. 344 345 By default, automatic HTML escaping is always applied. However, sometimes you 346 will not want this to occur (for example, if you're using the templating 347 system to create an email). To control automatic escaping inside your template, 348 wrap the affected content in the ``autoescape`` tag, like so:: 349 350 {% autoescape off %} 351 Hello {{ name }} 352 {% endautoescape %} 353 354 The auto-escaping tag passes its effect onto templates that extend the 355 current one as well as templates included via the ``include`` tag, just like 356 all block tags. 357 358 The ``autoescape`` tag takes either ``on`` or ``off`` as its argument. At times, you might want to force auto-escaping when it would otherwise be disabled. For example:: 359 360 Auto-escaping is on by default. Hello {{ name }} 361 362 {% autoescape off %} 363 This will not be auto-escaped: {{ data }}. 364 365 Nor this: {{ other_data }} 366 {% autoescape on %} 367 Auto-escaping applies again, {{ name }} 368 {% endautoescape %} 369 {% endautoescape %} 370 371 For individual variables, the ``safe`` filter can also be used to indicate 372 that the contents should not be automatically escaped:: 373 374 This will be escaped: {{ data }} 375 This will not be escaped: {{ data|safe }} 376 377 Think of *safe* as shorthand for *safe from further escaping* or *can be 378 safely interpreted as HTML*. In this example, if ``data`` contains ``'<a>'``, 379 the output will be:: 380 381 This will be escaped: <a> 382 This will not be escaped: <a> 383 384 Generally, you won't need to worry about auto-escaping very much. View 385 developers and custom filter authors need to think about when their data 386 shouldn't be escaped and mark it appropriately. They are in a better position 387 to know when that should happen than the template author, so it is their 388 responsibility. By default, all output is escaped unless the template 389 processor is explicitly told otherwise. 390 391 You should also note that if you are trying to write a template that might be 392 used in situations where automatic escaping is enabled or disabled and you 393 don't know which (such as when your template is included in other templates), 394 you can safely write as if you were in an ``{% autoescape off %}`` situation. 395 Scatter ``escape`` filters around for any variables that need escaping. When 396 auto-escaping is on, these extra filters won't change the output -- any 397 variables that use the ``escape`` filter do not have further automatic 398 escaping applied to them. 399 302 400 Using the built-in reference 303 401 ============================ … … 374 472 Built-in tag reference 375 473 ---------------------- 474 475 autoescape 476 ~~~~~~~~~~ 477 478 **New in Django development version** 479 480 Control the current auto-escaping behaviour. This tag takes either ``on`` or 481 ``off`` as an argument and that determines whether auto-escaping is in effect 482 inside the block. 483 484 When auto-escaping is in effect, all variable content has HTML escaping applied 485 to it before placing the result into the output (but after any filters have 486 been applied). This is equivalent to manually applying the ``escape`` filter 487 attached to each variable. 488 489 The only exceptions are variables that are already marked as 'safe' from 490 escaping, either by the code that populated the variable, or because it has 491 the ``safe`` or ``escape`` filters applied. 376 492 377 493 block … … 453 569 Sample usage:: 454 570 455 {% filter escape|lower %}571 {% filter force_escape|lower %} 456 572 This text will be HTML-escaped, and will appear in all lowercase. 457 573 {% endfilter %} … … 1077 1193 ~~~~~~ 1078 1194 1195 **New in Django development version:** The behaviour of this filter has 1196 changed slightly in the development version (the affects are only applied 1197 once, after all other filters). 1198 1079 1199 Escapes a string's HTML. Specifically, it makes these replacements: 1080 1200 … … 1084 1204 * ``'"'`` (double quote) to ``'"'`` 1085 1205 * ``"'"`` (single quote) to ``'''`` 1206 1207 The escaping is only applied when the string is output, so it does not matter 1208 where in a chained sequence of filters you put ``escape``: it will always be 1209 applied as though it were the last filter. If you want escaping to be applied 1210 immediately, use the ``force_escape`` filter. 1211 1212 Applying ``escape`` to a variable that would normally have auto-escaping 1213 applied to the result will only result in one round of escaping being done. So 1214 it is safe to use this function even in auto-escaping environments. If you want 1215 multiple escaping passes to be applied, use the ``force_escape`` filter. 1086 1216 1087 1217 filesizeformat … … 1141 1271 with an argument of ``-1``. 1142 1272 1273 force_escape 1274 ~~~~~~~~~~~~ 1275 1276 **New in Django development version** 1277 1278 Applies HTML escaping to a string (see the ``escape`` filter for details). 1279 This filter is applied *immediately* and returns a new, escaped string. This 1280 is useful in the rare cases where you need multiple escaping or want to apply 1281 other filters to the escaped results. Normally, you want to use the ``escape`` 1282 filter. 1283 1143 1284 get_digit 1144 1285 ~~~~~~~~~ … … 1264 1405 1265 1406 **Argument:** field size 1407 1408 safe 1409 ~~~~ 1410 1411 Marks a string as not requiring further HTML escaping prior to output. When 1412 autoescaping is off, this filter has no effect. 1266 1413 1267 1414 slice django/trunk/tests/regressiontests/defaultfilters/tests.py
r6647 r6671 195 195 u'a string to be mangled' 196 196 197 >>> escape(u'<some html & special characters > here')197 >>> force_escape(u'<some html & special characters > here') 198 198 u'<some html & special characters > here' 199 199 200 >>> escape(u'<some html & special characters > here ĐÅ€£')200 >>> force_escape(u'<some html & special characters > here ĐÅ€£') 201 201 u'<some html & special characters > here \xc4\x90\xc3\x85\xe2\x82\xac\xc2\xa3' 202 202 django/trunk/tests/regressiontests/forms/forms.py
r6379 r6671 1555 1555 >>> print t.render(Context({'form': UserRegistration(auto_id=False)})) 1556 1556 <form action=""> 1557 <p>Username: <input type="text" name="username" maxlength="10" /><br />Good luck picking a username that doesn 't already exist.</p>1557 <p>Username: <input type="text" name="username" maxlength="10" /><br />Good luck picking a username that doesn't already exist.</p> 1558 1558 <p>Password1: <input type="password" name="password1" /></p> 1559 1559 <p>Password2: <input type="password" name="password2" /></p> django/trunk/tests/regressiontests/forms/tests.py
r6625 r6671 51 51 'localflavor_uk_tests': localflavor_uk_tests, 52 52 'localflavor_us_tests': localflavor_us_tests, 53 'regression s_tests': regression_tests,53 'regression_tests': regression_tests, 54 54 'util_tests': util_tests, 55 55 'widgets_tests': widgets_tests, django/trunk/tests/regressiontests/humanize/tests.py
r5985 r6671 4 4 from django.utils.dateformat import DateFormat 5 5 from django.utils.translation import ugettext as _ 6 from django.utils.html import escape 6 7 7 8 add_to_builtins('django.contrib.humanize.templatetags.humanize') … … 16 17 t = Template('{{ test_content|%s }}' % method) 17 18 rendered = t.render(Context(locals())).strip() 18 self.assertEqual(rendered, result_list[index],19 self.assertEqual(rendered, escape(result_list[index]), 19 20 msg="%s test failed, produced %s, should've produced %s" % (method, rendered, result_list[index])) 20 21 django/trunk/tests/regressiontests/templates/tests.py
r6582 r6671 15 15 from django.template.loaders import app_directories, filesystem 16 16 from django.utils.translation import activate, deactivate, ugettext as _ 17 from django.utils.safestring import mark_safe 17 18 from django.utils.tzinfo import LocalTimezone 18 19 19 20 from unicode import unicode_tests 21 import filters 20 22 21 23 # Some other tests we would like to run … … 121 123 122 124 def test_templates(self): 123 # NOW and NOW_tz are used by timesince tag tests. 124 NOW = datetime.now() 125 NOW_tz = datetime.now(LocalTimezone(datetime.now())) 126 125 template_tests = self.get_template_tests() 126 filter_tests = filters.get_filter_tests() 127 128 # Quickly check that we aren't accidentally using a name in both 129 # template and filter tests. 130 overlapping_names = [name for name in filter_tests if name in 131 template_tests] 132 assert not overlapping_names, 'Duplicate test name(s): %s' % ', '.join(overlapping_names) 133 134 template_tests.update(filter_tests) 135 136 # Register our custom template loader. 137 def test_template_loader(template_name, template_dirs=None): 138 "A custom template loader that loads the unit-test templates." 139 try: 140 return (template_tests[template_name][0] , "test:%s" % template_name) 141 except KeyError: 142 raise template.TemplateDoesNotExist, template_name 143 144 old_template_loaders = loader.template_source_loaders 145 loader.template_source_loaders = [test_template_loader] 146 147 failures = [] 148 tests = template_tests.items() 149 tests.sort() 150 151 # Turn TEMPLATE_DEBUG off, because tests assume that. 152 old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False 153 154 # Set TEMPLATE_STRING_IF_INVALID to a known string 155 old_invalid = settings.TEMPLATE_STRING_IF_INVALID 156 expected_invalid_str = 'INVALID' 157 158 for name, vals in tests: 159 if isinstance(vals[2], tuple): 160 normal_string_result = vals[2][0] 161 invalid_string_result = vals[2][1] 162 if '%s' in invalid_string_result: 163 expected_invalid_str = 'INVALID %s' 164 invalid_string_result = invalid_string_result % vals[2][2] 165 template.invalid_var_format_string = True 166 else: 167 normal_string_result = vals[2] 168 invalid_string_result = vals[2] 169 170 if 'LANGUAGE_CODE' in vals[1]: 171 activate(vals[1]['LANGUAGE_CODE']) 172 else: 173 activate('en-us') 174 175 for invalid_str, result in [('', normal_string_result), 176 (expected_invalid_str, invalid_string_result)]: 177 settings.TEMPLATE_STRING_IF_INVALID = invalid_str 178 try: 179 test_template = loader.get_template(name) 180 output = self.render(test_template, vals) 181 except Exception, e: 182 if e.__class__ != result: 183 failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s" % (invalid_str, name, e.__class__, e)) 184 continue 185 if output != result: 186 failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output)) 187 188 if 'LANGUAGE_CODE' in vals[1]: 189 deactivate() 190 191 if template.invalid_var_format_string: 192 expected_invalid_str = 'INVALID' 193 template.invalid_var_format_string = False 194 195 loader.template_source_loaders = old_template_loaders 196 deactivate() 197 settings.TEMPLATE_DEBUG = old_td 198 settings.TEMPLATE_STRING_IF_INVALID = old_invalid 199 200 self.assertEqual(failures, [], '\n'.join(failures)) 201 202 def render(self, test_template, vals): 203 return test_template.render(template.Context(vals[1])) 204 205 def get_template_tests(self): 127 206 # SYNTAX -- 128 207 # 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class) 129 TEMPLATE_TESTS = { 130 131 ### BASIC SYNTAX ########################################################## 208 return { 209 ### BASIC SYNTAX ################################################ 132 210 133 211 # Plain text should go through the template parser untouched 134 212 'basic-syntax01': ("something cool", {}, "something cool"), 135 213 136 # Variables should be replaced with their value in the current context 214 # Variables should be replaced with their value in the current 215 # context 137 216 'basic-syntax02': ("{{ headline }}", {'headline':'Success'}, "Success"), 138 217 … … 241 320 242 321 # Escaped string as argument 243 'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'), 322 'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}', 323 {"var": None}, ' endquote" hah'), 244 324 245 325 # Variable as argument … … 761 841 # 'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year)) 762 842 763 ### TIMESINCE TAG ##################################################764 # Default compare with datetime.now()765 'timesince01' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),766 'timesince02' : ('{{ a|timesince }}', {'a':(datetime.now() - timedelta(days=1, minutes = 1))}, '1 day'),767 'timesince03' : ('{{ a|timesince }}', {'a':(datetime.now() -768 timedelta(hours=1, minutes=25, seconds = 10))}, '1 hour, 25 minutes'),769 770 # Compare to a given parameter771 'timesince04' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2), 'b':NOW + timedelta(days=1)}, '1 day'),772 'timesince05' : ('{{ a|timesince:b }}', {'a':NOW + timedelta(days=2, minutes=1), 'b':NOW + timedelta(days=2)}, '1 minute'),773 774 # Check that timezone is respected775 'timesince06' : ('{{ a|timesince:b }}', {'a':NOW_tz + timedelta(hours=8), 'b':NOW_tz}, '8 hours'),776 777 # Check times in the future.778 'timesince07' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(minutes=1, seconds=10)}, '0 minutes'),779 'timesince08' : ('{{ a|timesince }}', {'a':datetime.now() + timedelta(days=1, minutes=1)}, '0 minutes'),780 781 ### TIMEUNTIL TAG ##################################################782 # Default compare with datetime.now()783 'timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),784 'timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),785 'timeuntil03' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(hours=8, minutes=10, seconds = 10))}, '8 hours, 10 minutes'),786 787 # Compare to a given parameter788 'timeuntil04' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=1), 'b':NOW - timedelta(days=2)}, '1 day'),789 'timeuntil05' : ('{{ a|timeuntil:b }}', {'a':NOW - timedelta(days=2), 'b':NOW - timedelta(days=2, minutes=1)}, '1 minute'),790 791 # Check times in the past.792 'timeuntil07' : ('{{ a|timeuntil }}', {'a':datetime.now() - timedelta(minutes=1, seconds=10)}, '0 minutes'),793 'timeuntil08' : ('{{ a|timeuntil }}', {'a':datetime.now() - timedelta(days=1, minutes=1)}, '0 minutes'),794 795 843 ### URL TAG ######################################################## 796 844 # Successes … … 820 868 'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError), 821 869 'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError), 870 871 ### AUTOESCAPE TAG ############################################## 872 'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"), 873 'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"), 874 'autoescape-tag03': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"), 875 876 # Autoescape disabling and enabling nest in a predictable way. 877 'autoescape-tag04': ("{% autoescape off %}{{ first }} {% autoescape on%}{{ first }}{% endautoescape %}{% endautoescape %}", {"first": "<a>"}, "<a> <a>"), 878 879 'autoescape-tag05': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": "<b>first</b>"}, "<b>first</b>"), 880 881 # Strings (ASCII or unicode) already marked as "safe" are not 882 # auto-escaped 883 'autoescape-tag06': ("{{ first }}", {"first": mark_safe("<b>first</b>")}, "<b>first</b>"), 884 'autoescape-tag07': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": mark_safe(u"<b>Apple</b>")}, u"<b>Apple</b>"), 885 886 # String arguments to filters, if used in the result, are escaped, 887 # too. 888 'basic-syntax08': (r'{% autoescape on %}{{ var|default_if_none:" endquote\" hah" }}{% endautoescape %}', {"var": None}, ' endquote" hah'), 889 890 # The "safe" and "escape" filters cannot work due to internal 891 # implementation details (fortunately, the (no)autoescape block 892 # tags can be used in those cases) 893 'autoescape-filtertag01': ("{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError), 822 894 } 823 824 # Register our custom template loader.825 def test_template_loader(template_name, template_dirs=None):826 "A custom template loader that loads the unit-test templates."827 try:828 return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name)829 except KeyError:830 raise template.TemplateDoesNotExist, template_name831 832 old_template_loaders = loader.template_source_loaders833 loader.template_source_loaders = [test_template_loader]834 835 failures = []836 tests = TEMPLATE_TESTS.items()837 tests.sort()838 839 # Turn TEMPLATE_DEBUG off, because tests assume that.840 old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False841 842 # Set TEMPLATE_STRING_IF_INVALID to a known string843 old_invalid = settings.TEMPLATE_STRING_IF_INVALID844 expected_invalid_str = 'INVALID'845 846 for name, vals in tests:847 if isinstance(vals[2], tuple):848 normal_string_result = vals[2][0]849 invalid_string_result = vals[2][1]850 if '%s' in invalid_string_result:851 expected_invalid_str = 'INVALID %s'852 invalid_string_result = invalid_string_result % vals[2][2]853 template.invalid_var_format_string = True854 else:855 normal_string_result = vals[2]856 invalid_string_result = vals[2]857 858 if 'LANGUAGE_CODE' in vals[1]:859 activate(vals[1]['LANGUAGE_CODE'])860 else:861 activate('en-us')862 863 for invalid_str, result in [('', normal_string_result),864 (expected_invalid_str, invalid_string_result)]:865 settings.TEMPLATE_STRING_IF_INVALID = invalid_str866 try:867 output = loader.get_template(name).render(template.Context(vals[1]))868 except Exception, e:869 if e.__class__ != result:870 failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Got %s, exception: %s" % (invalid_str, name, e.__class__, e))871 continue872 if output != result:873 failures.append("Template test (TEMPLATE_STRING_IF_INVALID='%s'): %s -- FAILED. Expected %r, got %r" % (invalid_str, name, result, output))874 875 if 'LANGUAGE_CODE' in vals[1]:876 deactivate()877 878 if template.invalid_var_format_string:879 expected_invalid_str = 'INVALID'880 template.invalid_var_format_string = False881 882 loader.template_source_loaders = old_template_loaders883 deactivate()884 settings.TEMPLATE_DEBUG = old_td885 settings.TEMPLATE_STRING_IF_INVALID = old_invalid886 887 self.assertEqual(failures, [], '\n'.join(failures))888 895 889 896 if __name__ == "__main__":
